Index: frontend/node_modules/@ungap/structured-clone/.github/workflows/node.js.yml
===================================================================
--- frontend/node_modules/@ungap/structured-clone/.github/workflows/node.js.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/.github/workflows/node.js.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
+
+name: build
+
+on: [push, pull_request]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        node-version: [16]
+
+    steps:
+    - uses: actions/checkout@v2
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v2
+      with:
+        node-version: ${{ matrix.node-version }}
+        cache: 'npm'
+    - run: npm ci
+    - run: npm run build --if-present
+    - run: npm test
+    - run: npm run coverage --if-present
+    - name: Coveralls
+      uses: coverallsapp/github-action@master
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
Index: frontend/node_modules/@ungap/structured-clone/LICENSE
===================================================================
--- frontend/node_modules/@ungap/structured-clone/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2021, Andrea Giammarchi, @WebReflection
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
Index: frontend/node_modules/@ungap/structured-clone/README.md
===================================================================
--- frontend/node_modules/@ungap/structured-clone/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+# structuredClone polyfill
+
+[![Downloads](https://img.shields.io/npm/dm/@ungap/structured-clone.svg)](https://www.npmjs.com/package/@ungap/structured-clone) [![build status](https://github.com/ungap/structured-clone/actions/workflows/node.js.yml/badge.svg)](https://github.com/ungap/structured-clone/actions) [![Coverage Status](https://coveralls.io/repos/github/ungap/structured-clone/badge.svg?branch=main)](https://coveralls.io/github/ungap/structured-clone?branch=main)
+
+An env agnostic serializer and deserializer with recursion ability and types beyond *JSON* from the *HTML* standard itself.
+
+  * [Supported Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types)
+    * *not supported yet*: Blob, File, FileList, ImageBitmap, ImageData or others non *JS* types but typed arrays are supported without major issues, but u/int8, u/int16, and u/int32 are the only safely suppored (right now).
+    * *not possible to implement*: the `{transfer: []}` option can be passed but it's completely ignored.
+  * [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)
+  * [Serializer](https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal)
+  * [Deserializer](https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize)
+
+Serialized values can be safely stringified as *JSON* too, and deserialization resurrect all values, even recursive, or more complex than what *JSON* allows.
+
+
+### Examples
+
+Check the [100% test coverage](./test/index.js) to know even more.
+
+```js
+// as default export
+import structuredClone from '@ungap/structured-clone';
+const cloned = structuredClone({any: 'serializable'});
+
+// as independent serializer/deserializer
+import {serialize, deserialize} from '@ungap/structured-clone';
+
+// the result can be stringified as JSON without issues
+// even if there is recursive data, bigint values,
+// typed arrays, and so on
+const serialized = serialize({any: 'serializable'});
+
+// the result will be a replica of the original object
+const deserialized = deserialize(serialized);
+```
+
+#### Global Polyfill
+Note: Only monkey patch the global if needed. This polyfill works just fine as an explicit import: `import structuredClone from "@ungap/structured-clone"`
+```js
+// Attach the polyfill as a Global function
+import structuredClone from "@ungap/structured-clone";
+if (!("structuredClone" in globalThis)) {
+  globalThis.structuredClone = structuredClone;
+}
+
+// Or don't monkey patch
+import structuredClone from "@ungap/structured-clone"
+// Just use it in the file
+structuredClone()
+```
+
+**Note**: Do not attach this module's default export directly to the global scope, whithout a conditional guard to detect a native implementation. In environments where there is a native global implementation of `structuredClone()` already, assignment to the global object will result in an infinite loop when `globalThis.structuredClone()` is called. See the example above for a safe way to provide the polyfill globally in your project.
+
+### Extra Features
+
+There is no middle-ground between the structured clone algorithm and JSON:
+
+  * JSON is more relaxed about incompatible values: it just ignores these
+  * Structured clone is inflexible regarding incompatible values, yet it makes specialized instances impossible to reconstruct, plus it doesn't offer any helper, such as `toJSON()`, to make serialization possible, or better, with specific cases
+
+This module specialized `serialize` export offers, within the optional extra argument, a **lossy** property to avoid throwing when incompatible types are found down the road (function, symbol, ...), so that it is possible to send with less worrying about thrown errors.
+
+```js
+// as default export
+import structuredClone from '@ungap/structured-clone';
+const cloned = structuredClone(
+  {
+    method() {
+      // ignored, won't be cloned
+    },
+    special: Symbol('also ignored')
+  },
+  {
+    // avoid throwing
+    lossy: true,
+    // avoid throwing *and* looks for toJSON
+    json: true
+  }
+);
+```
+
+The behavior is the same found in *JSON* when it comes to *Array*, so that unsupported values will result as `null` placeholders instead.
+
+#### toJSON
+
+If `lossy` option is not enough, `json` will actually enforce `lossy` and also check for `toJSON` method when objects are parsed.
+
+Alternative, the `json` exports combines all features:
+
+```js
+import {stringify, parse} from '@ungap/structured-clone/json';
+
+parse(stringify({any: 'serializable'}));
+```
Index: frontend/node_modules/@ungap/structured-clone/cjs/deserialize.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/cjs/deserialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/cjs/deserialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,97 @@
+'use strict';
+const {
+  VOID, PRIMITIVE, ARRAY, OBJECT, DATE, REGEXP, MAP, SET, ERROR, BIGINT
+} = require('./types.js');
+
+const env = typeof self === 'object' ? self : globalThis;
+
+const guard = (name, init) => {
+  switch (name) {
+    case 'Function':
+    case 'SharedWorker':
+    case 'Worker':
+    case 'eval':
+    case 'setInterval':
+    case 'setTimeout':
+      throw new TypeError('unable to deserialize ' + name);
+  }
+  return new env[name](init);
+};
+
+const deserializer = ($, _) => {
+  const as = (out, index) => {
+    $.set(index, out);
+    return out;
+  };
+
+  const unpair = index => {
+    if ($.has(index))
+      return $.get(index);
+
+    const [type, value] = _[index];
+    switch (type) {
+      case PRIMITIVE:
+      case VOID:
+        return as(value, index);
+      case ARRAY: {
+        const arr = as([], index);
+        for (const index of value)
+          arr.push(unpair(index));
+        return arr;
+      }
+      case OBJECT: {
+        const object = as({}, index);
+        for (const [key, index] of value)
+          object[unpair(key)] = unpair(index);
+        return object;
+      }
+      case DATE:
+        return as(new Date(value), index);
+      case REGEXP: {
+        const {source, flags} = value;
+        return as(new RegExp(source, flags), index);
+      }
+      case MAP: {
+        const map = as(new Map, index);
+        for (const [key, index] of value)
+          map.set(unpair(key), unpair(index));
+        return map;
+      }
+      case SET: {
+        const set = as(new Set, index);
+        for (const index of value)
+          set.add(unpair(index));
+        return set;
+      }
+      case ERROR: {
+        const {name, message} = value;
+        return as(guard(name, message), index);
+      }
+      case BIGINT:
+        return as(BigInt(value), index);
+      case 'BigInt':
+        return as(Object(BigInt(value)), index);
+      case 'ArrayBuffer':
+        return as(new Uint8Array(value).buffer, value);
+      case 'DataView': {
+        const { buffer } = new Uint8Array(value);
+        return as(new DataView(buffer), value);
+      }
+    }
+    return as(guard(type, value), index);
+  };
+
+  return unpair;
+};
+
+/**
+ * @typedef {Array<string,any>} Record a type representation
+ */
+
+/**
+ * Returns a deserialized value from a serialized array of Records.
+ * @param {Record[]} serialized a previously serialized value.
+ * @returns {any}
+ */
+const deserialize = serialized => deserializer(new Map, serialized)(0);
+exports.deserialize = deserialize;
Index: frontend/node_modules/@ungap/structured-clone/cjs/index.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/cjs/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/cjs/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,27 @@
+'use strict';
+const {deserialize} = require('./deserialize.js');
+const {serialize} = require('./serialize.js');
+
+/**
+ * @typedef {Array<string,any>} Record a type representation
+ */
+
+/**
+ * Returns an array of serialized Records.
+ * @param {any} any a serializable value.
+ * @param {{transfer?: any[], json?: boolean, lossy?: boolean}?} options an object with
+ * a transfer option (ignored when polyfilled) and/or non standard fields that
+ * fallback to the polyfill if present.
+ * @returns {Record[]}
+ */
+Object.defineProperty(exports, '__esModule', {value: true}).default = typeof structuredClone === "function" ?
+  /* c8 ignore start */
+  (any, options) => (
+    options && ('json' in options || 'lossy' in options) ?
+      deserialize(serialize(any, options)) : structuredClone(any)
+  ) :
+  (any, options) => deserialize(serialize(any, options));
+  /* c8 ignore stop */
+
+exports.deserialize = deserialize;
+exports.serialize = serialize;
Index: frontend/node_modules/@ungap/structured-clone/cjs/json.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/cjs/json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/cjs/json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,24 @@
+'use strict';
+/*! (c) Andrea Giammarchi - ISC */
+
+const {deserialize} = require('./deserialize.js');
+const {serialize} = require('./serialize.js');
+
+const {parse: $parse, stringify: $stringify} = JSON;
+const options = {json: true, lossy: true};
+
+/**
+ * Revive a previously stringified structured clone.
+ * @param {string} str previously stringified data as string.
+ * @returns {any} whatever was previously stringified as clone.
+ */
+const parse = str => deserialize($parse(str));
+exports.parse = parse;
+
+/**
+ * Represent a structured clone value as string.
+ * @param {any} any some clone-able value to stringify.
+ * @returns {string} the value stringified.
+ */
+const stringify = any => $stringify(serialize(any, options));
+exports.stringify = stringify;
Index: frontend/node_modules/@ungap/structured-clone/cjs/package.json
===================================================================
--- frontend/node_modules/@ungap/structured-clone/cjs/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/cjs/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1 @@
+{"type":"commonjs"}
Index: frontend/node_modules/@ungap/structured-clone/cjs/serialize.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/cjs/serialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/cjs/serialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,170 @@
+'use strict';
+const {
+  VOID, PRIMITIVE, ARRAY, OBJECT, DATE, REGEXP, MAP, SET, ERROR, BIGINT
+} = require('./types.js');
+
+const EMPTY = '';
+
+const {toString} = {};
+const {keys} = Object;
+
+const typeOf = value => {
+  const type = typeof value;
+  if (type !== 'object' || !value)
+    return [PRIMITIVE, type];
+
+  const asString = toString.call(value).slice(8, -1);
+  switch (asString) {
+    case 'Array':
+      return [ARRAY, EMPTY];
+    case 'Object':
+      return [OBJECT, EMPTY];
+    case 'Date':
+      return [DATE, EMPTY];
+    case 'RegExp':
+      return [REGEXP, EMPTY];
+    case 'Map':
+      return [MAP, EMPTY];
+    case 'Set':
+      return [SET, EMPTY];
+    case 'DataView':
+      return [ARRAY, asString];
+  }
+
+  if (asString.includes('Array'))
+    return [ARRAY, asString];
+
+  if (asString.includes('Error'))
+    return [ERROR, asString];
+
+  return [OBJECT, asString];
+};
+
+const shouldSkip = ([TYPE, type]) => (
+  TYPE === PRIMITIVE &&
+  (type === 'function' || type === 'symbol')
+);
+
+const serializer = (strict, json, $, _) => {
+
+  const as = (out, value) => {
+    const index = _.push(out) - 1;
+    $.set(value, index);
+    return index;
+  };
+
+  const pair = value => {
+    if ($.has(value))
+      return $.get(value);
+
+    let [TYPE, type] = typeOf(value);
+    switch (TYPE) {
+      case PRIMITIVE: {
+        let entry = value;
+        switch (type) {
+          case 'bigint':
+            TYPE = BIGINT;
+            entry = value.toString();
+            break;
+          case 'function':
+          case 'symbol':
+            if (strict)
+              throw new TypeError('unable to serialize ' + type);
+            entry = null;
+            break;
+          case 'undefined':
+            return as([VOID], value);
+        }
+        return as([TYPE, entry], value);
+      }
+      case ARRAY: {
+        if (type) {
+          let spread = value;
+          if (type === 'DataView') {
+            spread = new Uint8Array(value.buffer);
+          }
+          else if (type === 'ArrayBuffer') {
+            spread = new Uint8Array(value);
+          }
+          return as([type, [...spread]], value);
+        }
+
+        const arr = [];
+        const index = as([TYPE, arr], value);
+        for (const entry of value)
+          arr.push(pair(entry));
+        return index;
+      }
+      case OBJECT: {
+        if (type) {
+          switch (type) {
+            case 'BigInt':
+              return as([type, value.toString()], value);
+            case 'Boolean':
+            case 'Number':
+            case 'String':
+              return as([type, value.valueOf()], value);
+          }
+        }
+
+        if (json && ('toJSON' in value))
+          return pair(value.toJSON());
+
+        const entries = [];
+        const index = as([TYPE, entries], value);
+        for (const key of keys(value)) {
+          if (strict || !shouldSkip(typeOf(value[key])))
+            entries.push([pair(key), pair(value[key])]);
+        }
+        return index;
+      }
+      case DATE:
+        return as([TYPE, value.toISOString()], value);
+      case REGEXP: {
+        const {source, flags} = value;
+        return as([TYPE, {source, flags}], value);
+      }
+      case MAP: {
+        const entries = [];
+        const index = as([TYPE, entries], value);
+        for (const [key, entry] of value) {
+          if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
+            entries.push([pair(key), pair(entry)]);
+        }
+        return index;
+      }
+      case SET: {
+        const entries = [];
+        const index = as([TYPE, entries], value);
+        for (const entry of value) {
+          if (strict || !shouldSkip(typeOf(entry)))
+            entries.push(pair(entry));
+        }
+        return index;
+      }
+    }
+
+    const {message} = value;
+    return as([TYPE, {name: type, message}], value);
+  };
+
+  return pair;
+};
+
+/**
+ * @typedef {Array<string,any>} Record a type representation
+ */
+
+/**
+ * Returns an array of serialized Records.
+ * @param {any} value a serializable value.
+ * @param {{json?: boolean, lossy?: boolean}?} options an object with a `lossy` or `json` property that,
+ *  if `true`, will not throw errors on incompatible types, and behave more
+ *  like JSON stringify would behave. Symbol and Function will be discarded.
+ * @returns {Record[]}
+ */
+ const serialize = (value, {json, lossy} = {}) => {
+  const _ = [];
+  return serializer(!(json || lossy), !!json, new Map, _)(value), _;
+};
+exports.serialize = serialize;
Index: frontend/node_modules/@ungap/structured-clone/cjs/types.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/cjs/types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/cjs/types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+'use strict';
+const VOID       = -1;
+exports.VOID = VOID;
+const PRIMITIVE  = 0;
+exports.PRIMITIVE = PRIMITIVE;
+const ARRAY      = 1;
+exports.ARRAY = ARRAY;
+const OBJECT     = 2;
+exports.OBJECT = OBJECT;
+const DATE       = 3;
+exports.DATE = DATE;
+const REGEXP     = 4;
+exports.REGEXP = REGEXP;
+const MAP        = 5;
+exports.MAP = MAP;
+const SET        = 6;
+exports.SET = SET;
+const ERROR      = 7;
+exports.ERROR = ERROR;
+const BIGINT     = 8;
+exports.BIGINT = BIGINT;
+// export const SYMBOL = 9;
Index: frontend/node_modules/@ungap/structured-clone/esm/deserialize.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/esm/deserialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/esm/deserialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,98 @@
+import {
+  VOID, PRIMITIVE,
+  ARRAY, OBJECT,
+  DATE, REGEXP, MAP, SET,
+  ERROR, BIGINT
+} from './types.js';
+
+const env = typeof self === 'object' ? self : globalThis;
+
+const guard = (name, init) => {
+  switch (name) {
+    case 'Function':
+    case 'SharedWorker':
+    case 'Worker':
+    case 'eval':
+    case 'setInterval':
+    case 'setTimeout':
+      throw new TypeError('unable to deserialize ' + name);
+  }
+  return new env[name](init);
+};
+
+const deserializer = ($, _) => {
+  const as = (out, index) => {
+    $.set(index, out);
+    return out;
+  };
+
+  const unpair = index => {
+    if ($.has(index))
+      return $.get(index);
+
+    const [type, value] = _[index];
+    switch (type) {
+      case PRIMITIVE:
+      case VOID:
+        return as(value, index);
+      case ARRAY: {
+        const arr = as([], index);
+        for (const index of value)
+          arr.push(unpair(index));
+        return arr;
+      }
+      case OBJECT: {
+        const object = as({}, index);
+        for (const [key, index] of value)
+          object[unpair(key)] = unpair(index);
+        return object;
+      }
+      case DATE:
+        return as(new Date(value), index);
+      case REGEXP: {
+        const {source, flags} = value;
+        return as(new RegExp(source, flags), index);
+      }
+      case MAP: {
+        const map = as(new Map, index);
+        for (const [key, index] of value)
+          map.set(unpair(key), unpair(index));
+        return map;
+      }
+      case SET: {
+        const set = as(new Set, index);
+        for (const index of value)
+          set.add(unpair(index));
+        return set;
+      }
+      case ERROR: {
+        const {name, message} = value;
+        return as(guard(name, message), index);
+      }
+      case BIGINT:
+        return as(BigInt(value), index);
+      case 'BigInt':
+        return as(Object(BigInt(value)), index);
+      case 'ArrayBuffer':
+        return as(new Uint8Array(value).buffer, value);
+      case 'DataView': {
+        const { buffer } = new Uint8Array(value);
+        return as(new DataView(buffer), value);
+      }
+    }
+    return as(guard(type, value), index);
+  };
+
+  return unpair;
+};
+
+/**
+ * @typedef {Array<string,any>} Record a type representation
+ */
+
+/**
+ * Returns a deserialized value from a serialized array of Records.
+ * @param {Record[]} serialized a previously serialized value.
+ * @returns {any}
+ */
+export const deserialize = serialized => deserializer(new Map, serialized)(0);
Index: frontend/node_modules/@ungap/structured-clone/esm/index.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/esm/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/esm/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+import {deserialize} from './deserialize.js';
+import {serialize} from './serialize.js';
+
+/**
+ * @typedef {Array<string,any>} Record a type representation
+ */
+
+/**
+ * Returns an array of serialized Records.
+ * @param {any} any a serializable value.
+ * @param {{transfer?: any[], json?: boolean, lossy?: boolean}?} options an object with
+ * a transfer option (ignored when polyfilled) and/or non standard fields that
+ * fallback to the polyfill if present.
+ * @returns {Record[]}
+ */
+export default typeof structuredClone === "function" ?
+  /* c8 ignore start */
+  (any, options) => (
+    options && ('json' in options || 'lossy' in options) ?
+      deserialize(serialize(any, options)) : structuredClone(any)
+  ) :
+  (any, options) => deserialize(serialize(any, options));
+  /* c8 ignore stop */
+
+export {deserialize, serialize};
Index: frontend/node_modules/@ungap/structured-clone/esm/json.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/esm/json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/esm/json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+/*! (c) Andrea Giammarchi - ISC */
+
+import {deserialize} from './deserialize.js';
+import {serialize} from './serialize.js';
+
+const {parse: $parse, stringify: $stringify} = JSON;
+const options = {json: true, lossy: true};
+
+/**
+ * Revive a previously stringified structured clone.
+ * @param {string} str previously stringified data as string.
+ * @returns {any} whatever was previously stringified as clone.
+ */
+export const parse = str => deserialize($parse(str));
+
+/**
+ * Represent a structured clone value as string.
+ * @param {any} any some clone-able value to stringify.
+ * @returns {string} the value stringified.
+ */
+export const stringify = any => $stringify(serialize(any, options));
Index: frontend/node_modules/@ungap/structured-clone/esm/serialize.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/esm/serialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/esm/serialize.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,171 @@
+import {
+  VOID, PRIMITIVE,
+  ARRAY, OBJECT,
+  DATE, REGEXP, MAP, SET,
+  ERROR, BIGINT
+} from './types.js';
+
+const EMPTY = '';
+
+const {toString} = {};
+const {keys} = Object;
+
+const typeOf = value => {
+  const type = typeof value;
+  if (type !== 'object' || !value)
+    return [PRIMITIVE, type];
+
+  const asString = toString.call(value).slice(8, -1);
+  switch (asString) {
+    case 'Array':
+      return [ARRAY, EMPTY];
+    case 'Object':
+      return [OBJECT, EMPTY];
+    case 'Date':
+      return [DATE, EMPTY];
+    case 'RegExp':
+      return [REGEXP, EMPTY];
+    case 'Map':
+      return [MAP, EMPTY];
+    case 'Set':
+      return [SET, EMPTY];
+    case 'DataView':
+      return [ARRAY, asString];
+  }
+
+  if (asString.includes('Array'))
+    return [ARRAY, asString];
+
+  if (asString.includes('Error'))
+    return [ERROR, asString];
+
+  return [OBJECT, asString];
+};
+
+const shouldSkip = ([TYPE, type]) => (
+  TYPE === PRIMITIVE &&
+  (type === 'function' || type === 'symbol')
+);
+
+const serializer = (strict, json, $, _) => {
+
+  const as = (out, value) => {
+    const index = _.push(out) - 1;
+    $.set(value, index);
+    return index;
+  };
+
+  const pair = value => {
+    if ($.has(value))
+      return $.get(value);
+
+    let [TYPE, type] = typeOf(value);
+    switch (TYPE) {
+      case PRIMITIVE: {
+        let entry = value;
+        switch (type) {
+          case 'bigint':
+            TYPE = BIGINT;
+            entry = value.toString();
+            break;
+          case 'function':
+          case 'symbol':
+            if (strict)
+              throw new TypeError('unable to serialize ' + type);
+            entry = null;
+            break;
+          case 'undefined':
+            return as([VOID], value);
+        }
+        return as([TYPE, entry], value);
+      }
+      case ARRAY: {
+        if (type) {
+          let spread = value;
+          if (type === 'DataView') {
+            spread = new Uint8Array(value.buffer);
+          }
+          else if (type === 'ArrayBuffer') {
+            spread = new Uint8Array(value);
+          }
+          return as([type, [...spread]], value);
+        }
+
+        const arr = [];
+        const index = as([TYPE, arr], value);
+        for (const entry of value)
+          arr.push(pair(entry));
+        return index;
+      }
+      case OBJECT: {
+        if (type) {
+          switch (type) {
+            case 'BigInt':
+              return as([type, value.toString()], value);
+            case 'Boolean':
+            case 'Number':
+            case 'String':
+              return as([type, value.valueOf()], value);
+          }
+        }
+
+        if (json && ('toJSON' in value))
+          return pair(value.toJSON());
+
+        const entries = [];
+        const index = as([TYPE, entries], value);
+        for (const key of keys(value)) {
+          if (strict || !shouldSkip(typeOf(value[key])))
+            entries.push([pair(key), pair(value[key])]);
+        }
+        return index;
+      }
+      case DATE:
+        return as([TYPE, value.toISOString()], value);
+      case REGEXP: {
+        const {source, flags} = value;
+        return as([TYPE, {source, flags}], value);
+      }
+      case MAP: {
+        const entries = [];
+        const index = as([TYPE, entries], value);
+        for (const [key, entry] of value) {
+          if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
+            entries.push([pair(key), pair(entry)]);
+        }
+        return index;
+      }
+      case SET: {
+        const entries = [];
+        const index = as([TYPE, entries], value);
+        for (const entry of value) {
+          if (strict || !shouldSkip(typeOf(entry)))
+            entries.push(pair(entry));
+        }
+        return index;
+      }
+    }
+
+    const {message} = value;
+    return as([TYPE, {name: type, message}], value);
+  };
+
+  return pair;
+};
+
+/**
+ * @typedef {Array<string,any>} Record a type representation
+ */
+
+/**
+ * Returns an array of serialized Records.
+ * @param {any} value a serializable value.
+ * @param {{json?: boolean, lossy?: boolean}?} options an object with a `lossy` or `json` property that,
+ *  if `true`, will not throw errors on incompatible types, and behave more
+ *  like JSON stringify would behave. Symbol and Function will be discarded.
+ * @returns {Record[]}
+ */
+ export const serialize = (value, {json, lossy} = {}) => {
+  const _ = [];
+  return serializer(!(json || lossy), !!json, new Map, _)(value), _;
+};
Index: frontend/node_modules/@ungap/structured-clone/esm/types.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/esm/types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/esm/types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,11 @@
+export const VOID       = -1;
+export const PRIMITIVE  = 0;
+export const ARRAY      = 1;
+export const OBJECT     = 2;
+export const DATE       = 3;
+export const REGEXP     = 4;
+export const MAP        = 5;
+export const SET        = 6;
+export const ERROR      = 7;
+export const BIGINT     = 8;
+// export const SYMBOL = 9;
Index: frontend/node_modules/@ungap/structured-clone/package.json
===================================================================
--- frontend/node_modules/@ungap/structured-clone/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+{
+  "name": "@ungap/structured-clone",
+  "version": "1.3.1",
+  "description": "A structuredClone polyfill",
+  "main": "./cjs/index.js",
+  "scripts": {
+    "build": "npm run cjs && npm run rollup:json && npm run test",
+    "cjs": "ascjs esm cjs",
+    "coverage": "c8 report --reporter=text-lcov > ./coverage/lcov.info",
+    "rollup:json": "rollup --config rollup/json.config.js",
+    "test": "c8 node test/index.js"
+  },
+  "keywords": [
+    "recursion",
+    "structured",
+    "clone",
+    "algorithm"
+  ],
+  "author": "Andrea Giammarchi",
+  "license": "ISC",
+  "devDependencies": {
+    "@rollup/plugin-node-resolve": "^16.0.3",
+    "@rollup/plugin-terser": "^1.0.0",
+    "ascjs": "^6.0.3",
+    "c8": "^11.0.0",
+    "coveralls": "^3.1.1",
+    "rollup": "^4.60.3"
+  },
+  "module": "./esm/index.js",
+  "type": "module",
+  "sideEffects": false,
+  "exports": {
+    ".": {
+      "import": "./esm/index.js",
+      "default": "./cjs/index.js"
+    },
+    "./json": {
+      "import": "./esm/json.js",
+      "default": "./cjs/json.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/ungap/structured-clone.git"
+  },
+  "bugs": {
+    "url": "https://github.com/ungap/structured-clone/issues"
+  },
+  "homepage": "https://github.com/ungap/structured-clone#readme"
+}
Index: frontend/node_modules/@ungap/structured-clone/structured-json.js
===================================================================
--- frontend/node_modules/@ungap/structured-clone/structured-json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/@ungap/structured-clone/structured-json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1 @@
+var StructuredJSON=function(e){"use strict";const r="object"==typeof self?self:globalThis,t=(e,t)=>{switch(e){case"Function":case"SharedWorker":case"Worker":case"eval":case"setInterval":case"setTimeout":throw new TypeError("unable to deserialize "+e)}return new r[e](t)},n=e=>((e,r)=>{const n=(r,t)=>(e.set(t,r),r),s=c=>{if(e.has(c))return e.get(c);const[a,o]=r[c];switch(a){case 0:case-1:return n(o,c);case 1:{const e=n([],c);for(const r of o)e.push(s(r));return e}case 2:{const e=n({},c);for(const[r,t]of o)e[s(r)]=s(t);return e}case 3:return n(new Date(o),c);case 4:{const{source:e,flags:r}=o;return n(new RegExp(e,r),c)}case 5:{const e=n(new Map,c);for(const[r,t]of o)e.set(s(r),s(t));return e}case 6:{const e=n(new Set,c);for(const r of o)e.add(s(r));return e}case 7:{const{name:e,message:r}=o;return n(t(e,r),c)}case 8:return n(BigInt(o),c);case"BigInt":return n(Object(BigInt(o)),c);case"ArrayBuffer":return n(new Uint8Array(o).buffer,o);case"DataView":{const{buffer:e}=new Uint8Array(o);return n(new DataView(e),o)}}return n(t(a,o),c)};return s})(new Map,e)(0),s="",{toString:c}={},{keys:a}=Object,o=e=>{const r=typeof e;if("object"!==r||!e)return[0,r];const t=c.call(e).slice(8,-1);switch(t){case"Array":return[1,s];case"Object":return[2,s];case"Date":return[3,s];case"RegExp":return[4,s];case"Map":return[5,s];case"Set":return[6,s];case"DataView":return[1,t]}return t.includes("Array")?[1,t]:t.includes("Error")?[7,t]:[2,t]},u=([e,r])=>0===e&&("function"===r||"symbol"===r),i=(e,{json:r,lossy:t}={})=>{const n=[];return((e,r,t,n)=>{const s=(e,r)=>{const s=n.push(e)-1;return t.set(r,s),s},c=n=>{if(t.has(n))return t.get(n);let[i,f]=o(n);switch(i){case 0:{let r=n;switch(f){case"bigint":i=8,r=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+f);r=null;break;case"undefined":return s([-1],n)}return s([i,r],n)}case 1:{if(f){let e=n;return"DataView"===f?e=new Uint8Array(n.buffer):"ArrayBuffer"===f&&(e=new Uint8Array(n)),s([f,[...e]],n)}const e=[],r=s([i,e],n);for(const r of n)e.push(c(r));return r}case 2:{if(f)switch(f){case"BigInt":return s([f,n.toString()],n);case"Boolean":case"Number":case"String":return s([f,n.valueOf()],n)}if(r&&"toJSON"in n)return c(n.toJSON());const t=[],l=s([i,t],n);for(const r of a(n))!e&&u(o(n[r]))||t.push([c(r),c(n[r])]);return l}case 3:return s([i,n.toISOString()],n);case 4:{const{source:e,flags:r}=n;return s([i,{source:e,flags:r}],n)}case 5:{const r=[],t=s([i,r],n);for(const[t,s]of n)(e||!u(o(t))&&!u(o(s)))&&r.push([c(t),c(s)]);return t}case 6:{const r=[],t=s([i,r],n);for(const t of n)!e&&u(o(t))||r.push(c(t));return t}}const{message:l}=n;return s([i,{name:f,message:l}],n)};return c})(!(r||t),!!r,new Map,n)(e),n},{parse:f,stringify:l}=JSON,w={json:!0,lossy:!0};return e.parse=e=>n(f(e)),e.stringify=e=>l(i(e,w)),e}({});
