diff --git a/dist/index.html b/dist/index.html
new file mode 100644
index 0000000..ebfab2d
--- /dev/null
+++ b/dist/index.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0f044e4
--- /dev/null
+++ b/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "browser-webapp",
+ "version": "0.1.0",
+ "type": "module",
+ "devDependencies": {
+ "@lumeweb/presetter-kernel-module-preset": "^0.1.0-develop.1",
+ "presetter": "*"
+ },
+ "readme": "ERROR: No README data found!",
+ "_id": "browser-webapp@0.1.0",
+ "scripts": {
+ "prepare": "presetter bootstrap",
+ "build": "run build",
+ "semantic-release": "semantic-release"
+ },
+ "dependencies": {
+ "@helia/unixfs": "^1.4.2",
+ "@lumeweb/kernel-dns-client": "^0.1.0-develop.7",
+ "@lumeweb/kernel-eth-client": "^0.1.0-develop.16",
+ "@lumeweb/kernel-handshake-client": "^0.1.0-develop.8",
+ "@lumeweb/kernel-ipfs-client": "^0.1.0-develop.24",
+ "@lumeweb/kernel-network-registry-client": "^0.1.0-develop.9",
+ "@lumeweb/kernel-peer-discovery-client": "^0.0.2-develop.16",
+ "@lumeweb/kernel-swarm-client": "^0.1.0-develop.10",
+ "@lumeweb/libkernel": "^0.1.0-develop.63",
+ "@lumeweb/tld-enum": "^0.1.0-develop.1",
+ "cheerio": "^1.0.0-rc.12",
+ "file-type": "^18.5.0",
+ "is-ipfs": "^8.0.1"
+ }
+}
diff --git a/src/clients.ts b/src/clients.ts
new file mode 100644
index 0000000..aff54f5
--- /dev/null
+++ b/src/clients.ts
@@ -0,0 +1,25 @@
+import { createClient as createDnsClient } from "@lumeweb/kernel-dns-client";
+import { createClient as createIpfsClient } from "@lumeweb/kernel-ipfs-client";
+import { createClient as createSwarmClient } from "@lumeweb/kernel-swarm-client";
+import { createClient as createPeerDiscoveryClient } from "@lumeweb/kernel-peer-discovery-client";
+import { createClient as createNetworkRegistryClient } from "@lumeweb/kernel-network-registry-client";
+import { createClient as createHandshakeClient } from "@lumeweb/kernel-handshake-client";
+import { createClient as createEthClient } from "@lumeweb/kernel-eth-client";
+
+const dnsClient = createDnsClient();
+const ipfsClient = createIpfsClient();
+const swarmClient = createSwarmClient();
+const peerDiscoveryClient = createPeerDiscoveryClient();
+const networkRegistryClient = createNetworkRegistryClient();
+const handshakeClient = createHandshakeClient();
+const ethClient = createEthClient();
+
+export {
+ dnsClient,
+ ipfsClient,
+ swarmClient,
+ peerDiscoveryClient,
+ networkRegistryClient,
+ handshakeClient,
+ ethClient,
+};
diff --git a/src/contentProcessor.ts b/src/contentProcessor.ts
new file mode 100644
index 0000000..d3f1f39
--- /dev/null
+++ b/src/contentProcessor.ts
@@ -0,0 +1,19 @@
+import { ContentFilter } from "./types.js";
+
+export class ContentProcessor {
+ private filters: ContentFilter[] = [];
+
+ registerFilter(filter: ContentFilter) {
+ this.filters.push(filter);
+ }
+
+ async process(response: Response, mimeType: string): Promise {
+ let processedResponse = response;
+
+ for (const filter of this.filters) {
+ processedResponse = await filter.process(processedResponse, mimeType);
+ }
+
+ return processedResponse;
+ }
+}
diff --git a/src/filters/urlRewrite.ts b/src/filters/urlRewrite.ts
new file mode 100644
index 0000000..6446322
--- /dev/null
+++ b/src/filters/urlRewrite.ts
@@ -0,0 +1,48 @@
+import { ContentFilter } from "src/types.js";
+import { getTld } from "@lumeweb/libresolver";
+import tldEnum from "@lumeweb/tld-enum";
+import * as cheerio from "cheerio";
+
+export default class URLRewriteFilter implements ContentFilter {
+ async process(response: Response, mimeType: string): Promise {
+ if (mimeType !== "text/html") {
+ return response;
+ }
+
+ let html = await response.text();
+
+ const $ = cheerio.load(html);
+ ["a", "link", "script", "img"].forEach((tag) => {
+ $.root()
+ .find(tag)
+ .each((index, element) => {
+ let attrName = ["a", "link"].includes(tag) ? "href" : "src";
+ let urlValue = $(element).attr(attrName);
+
+ if (urlValue) {
+ if (!isICANN(urlValue)) {
+ if (urlValue.startsWith("/")) {
+ $(element).attr(attrName, `/browse${urlValue}`);
+ } else if (urlValue.startsWith("http")) {
+ $(element).attr(attrName, `/browse/${urlValue}`);
+ }
+ }
+ }
+ });
+ });
+
+ return new Response($.html(), {
+ headers: response.headers,
+ });
+ }
+}
+
+function isICANN(url: string) {
+ try {
+ const parsedUrl = new URL(url);
+ const domain = parsedUrl.hostname;
+ return tldEnum.list.includes(getTld(domain));
+ } catch (e) {
+ return false;
+ }
+}
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..6cc0011
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,94 @@
+import * as kernel from "@lumeweb/libkernel/kernel";
+import {
+ dnsClient,
+ ethClient,
+ handshakeClient,
+ ipfsClient,
+ networkRegistryClient,
+ peerDiscoveryClient,
+ swarmClient,
+} from "./clients.js";
+import { ed25519 } from "@lumeweb/libkernel";
+
+document.addEventListener("DOMContentLoaded", () =>
+ document.getElementById("go-button")?.addEventListener("click", () => {
+ let input = (
+ document.getElementById("address-bar") as HTMLInputElement
+ ).value.trim();
+
+ // If the input doesn't contain a protocol, assume it's http
+ if (!input.match(/^https?:\/\//)) {
+ input = `http://${input}`;
+ }
+
+ try {
+ // Try to parse it as a URL
+ const url = new URL(input);
+
+ // Update the iframe's src attribute
+ const iframe = document.getElementById(
+ "web-content",
+ ) as HTMLIFrameElement;
+ iframe.src = `/browse/${url.hostname}${url.pathname}${url.search}${url.hash}`;
+ } catch (e) {
+ // Handle invalid URLs here, if needed
+ console.error("Invalid URL:", e);
+ }
+ }),
+);
+
+let BOOT_FUNCTIONS: (() => Promise)[] = [];
+
+async function boot() {
+ await kernel.init();
+ await kernel.login(ed25519.utils.randomPrivateKey());
+
+ const reg = await navigator.serviceWorker.register("/sw.js");
+ await reg.update();
+
+ await kernel.serviceWorkerReady();
+
+ BOOT_FUNCTIONS.push(
+ async () =>
+ await swarmClient.addRelay(
+ "2d7ae1517caf4aae4de73c6d6f400765d2dd00b69d65277a29151437ef1c7d1d",
+ ),
+ );
+
+ // IRC
+ BOOT_FUNCTIONS.push(
+ async () =>
+ await peerDiscoveryClient.register(
+ "zdiN5eJ3RfHpZHTYorGxBt1GCsrGJYV9GprwVWkj8snGsjWSrptFm8BtQX",
+ ),
+ );
+ BOOT_FUNCTIONS.push(
+ async () => await networkRegistryClient.registerType("content"),
+ );
+ BOOT_FUNCTIONS.push(
+ async () => await networkRegistryClient.registerType("blockchain"),
+ );
+ BOOT_FUNCTIONS.push(async () => await handshakeClient.register());
+ BOOT_FUNCTIONS.push(async () => await ethClient.register());
+ BOOT_FUNCTIONS.push(async () => await ipfsClient.register());
+
+ const resolvers = [
+ "zdiJdDdBJWAdYFTcRa9So5TQQ9f1pYMiMy4dqYcKp9imomQtR11LJUyJyV", // CID
+ "zdiKvnZYNjDqXaM8uF3pGEs7Tt6jqGc7t7M4eqbvJwpkTnrZymncfUW9Cj", // ENS
+ "zrjEH3iojPLr7986o7iCn9THBmJmHiuDWmS1G6oT8DnfuFM", // HNS
+ ];
+
+ for (const resolver of resolvers) {
+ BOOT_FUNCTIONS.push(async () => dnsClient.registerResolver(resolver));
+ }
+
+ await bootup();
+}
+
+async function bootup() {
+ for (const entry of Object.entries(BOOT_FUNCTIONS)) {
+ await entry[1]();
+ }
+}
+
+document.addEventListener("DOMContentLoaded", boot);
diff --git a/src/messages.ts b/src/messages.ts
new file mode 100644
index 0000000..642fb27
--- /dev/null
+++ b/src/messages.ts
@@ -0,0 +1,123 @@
+import exchangeCommunicationKeys from "./messages/exchangeCommunicationKeys.js";
+import {
+ deleteQuery,
+ getAuthStatus,
+ getAuthStatusKnown,
+ getLoggedInDefer,
+ getQueries,
+ getQuery,
+ resetLoggedInDefer,
+ setAuthStatus,
+ setAuthStatusKnown,
+ getAuthStatusDefer,
+} from "./vars.js";
+const kernelMessageHandlers = {
+ exchangeCommunicationKeys,
+};
+
+export async function handleIncomingMessage(event: MessageEvent) {
+ if (event.source === null) {
+ return;
+ }
+ if (event.source === window) {
+ return;
+ }
+
+ const data = event.data?.data;
+ if (event.data.method === "log") {
+ if (data?.isErr === false) {
+ console.log(data.message);
+ return;
+ }
+ console.error(data.message);
+ }
+
+ if (event.data.method === "kernelAuthStatus") {
+ setAuthStatus(data);
+ if (!getAuthStatusKnown()) {
+ getAuthStatusDefer().resolve();
+ setAuthStatusKnown(true);
+ console.log("bootloader is now initialized");
+ if (!getAuthStatus().loginComplete) {
+ console.log("user is not logged in: waiting until login is confirmed");
+ } else {
+ getLoggedInDefer().resolve();
+ }
+ if (getAuthStatus().logoutComplete) {
+ resetLoggedInDefer();
+ setAuthStatusKnown(false);
+ }
+ }
+ return;
+ }
+
+ if (!("nonce" in event.data)) {
+ (event.source as WindowProxy).postMessage(
+ {
+ nonce: "N/A",
+ method: "response",
+ err: "message sent to kernel with no nonce",
+ },
+ event.origin,
+ );
+ return;
+ }
+
+ if (!("method" in event.data)) {
+ (event.source as WindowProxy).postMessage(
+ {
+ nonce: event.data.nonce,
+ method: "response",
+ err: "message sent to kernel with no method",
+ },
+ event.origin,
+ );
+ return;
+ }
+
+ if (event.data.method in kernelMessageHandlers) {
+ let response;
+
+ try {
+ response = await kernelMessageHandlers[event.data.method](
+ event.data.data,
+ );
+ } catch (e: any) {
+ response = { err: (e as Error).message };
+ }
+
+ (event.source as WindowProxy).postMessage(
+ {
+ nonce: event.data.nonce,
+ data: response,
+ },
+ event.origin,
+ );
+ return;
+ }
+ if (!(event.data.nonce in getQueries())) {
+ return;
+ }
+
+ let receiveResult = getQuery(event.data.nonce);
+ if (event.data.method === "response") {
+ deleteQuery(event.data.nonce);
+ }
+
+ receiveResult?.(event.data);
+
+ if (["moduleCall", "response"].includes(event.data.method)) {
+ return;
+ }
+
+ (event.source as WindowProxy).postMessage(
+ {
+ nonce: event.data.nonce,
+ method: "response",
+ err:
+ "unrecognized method (user may need to log in): " + event.data.method,
+ },
+ event.origin,
+ );
+ return;
+}
diff --git a/src/messages/exchangeCommunicationKeys.ts b/src/messages/exchangeCommunicationKeys.ts
new file mode 100644
index 0000000..ca1a7b2
--- /dev/null
+++ b/src/messages/exchangeCommunicationKeys.ts
@@ -0,0 +1,11 @@
+import { bytesToHex, hexToBytes } from "@lumeweb/libweb";
+import {
+ getCommunicationPubKey,
+ setFrontendCommunicationPubkey,
+} from "../vars.js";
+
+export default function (data: any) {
+ setFrontendCommunicationPubkey(hexToBytes(data));
+
+ return bytesToHex(getCommunicationPubKey());
+}
diff --git a/src/mimes.ts b/src/mimes.ts
new file mode 100644
index 0000000..a49866d
--- /dev/null
+++ b/src/mimes.ts
@@ -0,0 +1,10 @@
+const extToMimes = new Map(
+ Object.entries({
+ html: "text/html",
+ xhtml: "application/xhtml+xml",
+ xml: "application/xml",
+ })
+);
+Object.freeze(extToMimes);
+
+export default extToMimes;
diff --git a/src/providerManager.ts b/src/providerManager.ts
new file mode 100644
index 0000000..e6f8af7
--- /dev/null
+++ b/src/providerManager.ts
@@ -0,0 +1,39 @@
+import { ContentProcessor } from "./contentProcessor.js";
+import { ContentProvider } from "./types.js";
+import { DNSRecord, DNSResult } from "@lumeweb/libresolver";
+import { URL } from "url";
+
+export class ProviderManager {
+ private providers: ContentProvider[] = [];
+
+ private _processor = new ContentProcessor();
+
+ get processor(): ContentProcessor {
+ return this._processor;
+ }
+
+ register(provider: ContentProvider) {
+ this.providers.push(provider);
+ }
+
+ async fetch(dnsResult: DNSResult, path: string): Promise {
+ for (const record of dnsResult.records) {
+ for (const provider of this.providers) {
+ if (provider.supports(record.value)) {
+ const content = await provider.fetchContent(record.value, path);
+
+ if (content.headers.get("Content-Type")) {
+ return this._processor.process(
+ content,
+ content.headers.get("Content-Type")!,
+ );
+ }
+
+ return content;
+ }
+ }
+ }
+
+ throw new Error("No suitable provider found.");
+ }
+}
diff --git a/src/providers/ipfs.ts b/src/providers/ipfs.ts
new file mode 100644
index 0000000..325a54b
--- /dev/null
+++ b/src/providers/ipfs.ts
@@ -0,0 +1,141 @@
+import { ContentProvider } from "src/types.js";
+import { ipfsPath, ipnsPath, path as checkPath } from "is-ipfs";
+import { createClient } from "@lumeweb/kernel-ipfs-client";
+import { CID } from "multiformats/cid";
+import type { UnixFSStats } from "@helia/unixfs";
+import * as nodePath from "path";
+import { fileTypeFromBuffer } from "file-type";
+import extToMimes from "../mimes.js";
+import { URL } from "url";
+
+export default class IPFSProvider implements ContentProvider {
+ private _client = createClient();
+ async fetchContent(
+ uri: string,
+ path: string,
+ query?: string,
+ ): Promise {
+ let cid = translatePath(uri);
+ let stat: UnixFSStats | null = null;
+ let urlPath = path;
+ const parsedPath = nodePath.parse(urlPath);
+ let err;
+ try {
+ if (ipnsPath(cid)) {
+ const cidHash = cid.replace("/ipns/", "");
+ cid = await this._client.ipns(cidHash);
+ cid = `/ipfs/${cid}`;
+ }
+
+ if (ipfsPath(cid)) {
+ cid = CID.parse(cid.replace("/ipfs/", "")).toV1().toString();
+ stat = await this._client.stat(cid);
+ }
+ } catch (e) {
+ err = (e as Error).message;
+ }
+
+ if (!err && stat?.type === "directory") {
+ if (!parsedPath.base.length || !parsedPath.ext.length) {
+ let found = false;
+ for (const indexFile of ["index.html", "index.htm"]) {
+ try {
+ const subPath = nodePath.join(urlPath, indexFile);
+ await this._client.stat(cid, {
+ path: subPath,
+ });
+ urlPath = subPath;
+ found = true;
+ break;
+ } catch {}
+ }
+
+ if (!found) {
+ err = "404";
+ }
+ } else {
+ try {
+ await this._client.stat(cid, {
+ path: urlPath,
+ });
+ } catch {
+ err = "404";
+ }
+ }
+
+ if (err) {
+ throw new Error(err);
+ }
+ }
+
+ let bufferRead = 0;
+ const fileTypeBufferLength = 4100;
+ const mimeBuffer: Uint8Array[] = [];
+ let reader = await this._client.cat(cid, { path: urlPath });
+
+ for await (const chunk of reader.iterable()) {
+ if (bufferRead < fileTypeBufferLength) {
+ if (chunk.length >= fileTypeBufferLength) {
+ mimeBuffer.push(chunk.slice(0, fileTypeBufferLength));
+ bufferRead += fileTypeBufferLength;
+ } else {
+ mimeBuffer.push(chunk);
+ bufferRead += chunk.length;
+ }
+
+ if (bufferRead >= fileTypeBufferLength) {
+ reader.abort();
+ break;
+ }
+ } else {
+ reader.abort();
+ break;
+ }
+ }
+
+ let mime;
+
+ if (bufferRead >= fileTypeBufferLength) {
+ const totalLength = mimeBuffer.reduce((acc, val) => acc + val.length, 0);
+ const concatenated = new Uint8Array(totalLength);
+ let offset = 0;
+ for (const chunk of mimeBuffer) {
+ concatenated.set(chunk, offset);
+ offset += chunk.length;
+ }
+ mime = await fileTypeFromBuffer(concatenated);
+
+ if (!mime) {
+ const ext = nodePath.parse(urlPath).ext.replace(".", "");
+ if (extToMimes.has(ext)) {
+ mime = extToMimes.get(ext);
+ }
+ }
+ }
+
+ reader = await this._client.cat(cid, { path: urlPath });
+
+ const stream = new ReadableStream({
+ async start(controller) {
+ for await (const chunk of reader.iterable()) {
+ controller.enqueue(chunk);
+ }
+ controller.close();
+ },
+ });
+
+ return new Response(stream, {
+ headers: {
+ "Content-Type": mime ?? undefined,
+ },
+ });
+ }
+
+ supports(uri: string): boolean {
+ return checkPath(translatePath(uri));
+ }
+}
+
+function translatePath(uri: string) {
+ return uri.replace(/:\/\//, "/").replace(/^/, "/");
+}
diff --git a/src/sw.ts b/src/sw.ts
new file mode 100644
index 0000000..55c841f
--- /dev/null
+++ b/src/sw.ts
@@ -0,0 +1,69 @@
+import { createClient as createDnsClient } from "@lumeweb/kernel-dns-client";
+import { ProviderManager } from "./providerManager.js";
+import IPFSProvider from "./providers/ipfs.js";
+import URLRewriteFilter from "./filters/urlRewrite.js";
+
+const dnsClient = createDnsClient();
+
+const providerManager = new ProviderManager();
+providerManager.register(new IPFSProvider());
+providerManager.processor.registerFilter(new URLRewriteFilter());
+
+globalThis.postMessage = async (...args) => {
+ // @ts-ignore
+ let ret = await clients.matchAll({ includeUncontrolled: true });
+ ret.forEach((item) => item.postMessage(...args));
+
+ if (!ret.length) {
+ const cb = (event) => {
+ // @ts-ignore
+ postMessage(...args);
+ self.removeEventListener("activate", cb);
+ };
+ self.addEventListener("activate", cb);
+ }
+};
+
+self.addEventListener("activate", (event) => {
+ // @ts-ignore
+ event.waitUntil(
+ (async () => {
+ // @ts-ignore
+ await clients.claim();
+ // @ts-ignore
+ })(),
+ );
+});
+
+addEventListener("fetch", (event: any) => {
+ event.respondWith(
+ (async () => {
+ const req = event.request;
+ const url = new URL(req.url);
+
+ if (
+ ["/index.html", "/index.js", "/"].includes(url.pathname) ||
+ !url.pathname.startsWith("/browse/")
+ ) {
+ return fetch(event.request).then((response: any) => {
+ response.redirectToFinalURL = true;
+ return response;
+ });
+ }
+
+ let realUrl = url.pathname.replace(/^\/browse\//, "").replace(/\/$/, "");
+
+ if (!realUrl.match(/^https?:\/\//)) {
+ realUrl = `http://${realUrl}`;
+ }
+ // Use your existing communication framework to resolve DNS.
+ const dnsResult = await dnsClient.resolve(new URL(realUrl).hostname);
+
+ if (!dnsResult.error && dnsResult.records.length > 0) {
+ return providerManager.fetch(dnsResult, new URL(realUrl).pathname);
+ }
+
+ return new Response("Sorry, that is not a valid web3 website.");
+ })(),
+ );
+});
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..5ee1294
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,12 @@
+export interface ContentProvider {
+ supports: (uri: string) => boolean;
+ fetchContent: (
+ uri: string,
+ path: string,
+ query?: string,
+ ) => Promise;
+}
+
+export interface ContentFilter {
+ process: (response: Response, mineType: string) => Promise;
+}
diff --git a/src/util.ts b/src/util.ts
new file mode 100644
index 0000000..630a675
--- /dev/null
+++ b/src/util.ts
@@ -0,0 +1,53 @@
+import {
+ getKernelLoaded,
+ getLoginComplete,
+ getLogoutComplete,
+} from "./vars.js";
+import { objAsString } from "@lumeweb/libkernel";
+
+export function sendAuthUpdate() {
+ window.parent.postMessage(
+ {
+ method: "kernelAuthStatus",
+ data: {
+ loginComplete: getLoginComplete(),
+ kernelLoaded: getKernelLoaded(),
+ logoutComplete: getLogoutComplete(),
+ },
+ },
+ "*",
+ );
+}
+
+function bootloaderWLog(isErr: boolean, ...inputs: any) {
+ // Build the message, each item gets its own line. We do this because items
+ // are often full objects.
+ let message = "[lumeweb-kernel-bootloader]";
+ for (let i = 0; i < inputs.length; i++) {
+ message += "\n";
+ message += objAsString(inputs[i]);
+ }
+
+ // Create the log by sending it to the parent.
+ window.parent.postMessage(
+ {
+ method: "log",
+ data: {
+ isErr,
+ message,
+ },
+ },
+ "*",
+ );
+}
+
+export function log(...inputs: any) {
+ bootloaderWLog(false, ...inputs);
+}
+export function logErr(...inputs: any) {
+ bootloaderWLog(true, ...inputs);
+}
+
+export function reloadKernel() {
+ window.location.reload();
+}
diff --git a/src/vars.ts b/src/vars.ts
new file mode 100644
index 0000000..5611c69
--- /dev/null
+++ b/src/vars.ts
@@ -0,0 +1,103 @@
+import { x25519 } from "@noble/curves/ed25519";
+import { defer } from "@lumeweb/libkernel/module";
+import { KernelAuthStatus } from "@lumeweb/libkernel";
+
+let queriesNonce = 1;
+let queries: any = {};
+let authStatus: KernelAuthStatus;
+let authStatusKnown = false;
+let authStatusDefer = defer();
+let loggedInDefer = defer();
+
+const store = new Map(
+ Object.entries({
+ loginComplete: false,
+ logoutComplete: false,
+ kernelLoaded: "not yet",
+ communicationKey: null,
+ frontendCommunicationPubKey: null,
+ }),
+);
+
+export function setLoginComplete(status: boolean) {
+ store.set("loginComplete", status);
+}
+export function getLoginComplete(): boolean {
+ return store.get("loginComplete");
+}
+export function setLogoutComplete(status: boolean) {
+ store.set("logoutComplete", status);
+}
+export function getLogoutComplete(): boolean {
+ return store.get("logoutComplete");
+}
+export function setKernelLoaded(status: string) {
+ store.set("kernelLoaded", status);
+}
+
+export function getKernelLoaded(): string {
+ return store.get("kernelLoaded");
+}
+
+export function getCommunicationKey(): Uint8Array {
+ if (!store.get("communicationKey")) {
+ store.set("communicationKey", x25519.utils.randomPrivateKey());
+ }
+
+ return store.get("communicationKey");
+}
+
+export function getCommunicationPubKey() {
+ return x25519.getPublicKey(getCommunicationKey());
+}
+
+export function getFrontendCommunicationPubkey(): Uint8Array {
+ return store.get("frontendCommunicationPubKey");
+}
+
+export function setFrontendCommunicationPubkey(key: Uint8Array) {
+ store.set("frontendCommunicationPubKey", key);
+}
+export function getAuthStatusDefer() {
+ return authStatusDefer;
+}
+export function getQueriesNonce(): number {
+ return queriesNonce;
+}
+export function addQuery(nonce: any, func: Function) {
+ queries[nonce] = func;
+}
+
+export function increaseQueriesNonce() {
+ queriesNonce++;
+}
+export function setAuthStatus(status: KernelAuthStatus) {
+ authStatus = status;
+}
+
+export function getAuthStatusKnown() {
+ return authStatusKnown;
+}
+export function setAuthStatusKnown(status: boolean) {
+ authStatusKnown = status;
+}
+export function getAuthStatus(): KernelAuthStatus {
+ return authStatus;
+}
+export function getLoggedInDefer() {
+ return loggedInDefer;
+}
+export function resetLoggedInDefer() {
+ loggedInDefer = defer();
+}
+export function getQueries() {
+ return queries;
+}
+
+export function getQuery(nonce: any) {
+ return queries[nonce];
+}
+
+export function deleteQuery(nonce: any) {
+ delete queries[nonce];
+}