= ({ name, total, value }) => {
- return (
-
-
- {name}
-
-
- {toGigabytes(value)} / {toGigabytes(total)}{" "}
- {((value / total) * 100).toFixed(2)} %
-
-
- );
-};
-
-const toGigabytes = (input: number) => {
- return input > 1000 ? input / 1000 + "GB" : input + "MB";
-};
-
-export default SystemItem;
diff --git a/app/app/_components/WelcomeContainer/index.tsx b/app/app/_components/WelcomeContainer/index.tsx
deleted file mode 100644
index f8e043dcc..000000000
--- a/app/app/_components/WelcomeContainer/index.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import Image from "next/image";
-import SystemStatus from "../SystemStatus";
-import { SidebarButton } from "../SidebarButton";
-
-const Welcome: React.FC = () => {
- const data = {
- name: "LlaMa 2 - Hermes 7B (Q4_K_M)",
- type: "7B",
- author: "Architecture Llama",
- description:
- "Primary intended uses The primary use of LLaMA is research on large language models, including: exploring potential applications such as question answering, natural language understanding or reading comprehension, understanding capabilities and limitations of current language models, and developing techniques to improve those, evaluating and mitigating biases, risks, toxic and harmful content generations, hallucinations.",
- isRecommend: true,
- storage: 3780,
- required: "8GB+ RAM",
- };
- const system = [
- {
- name: "GPU",
- value: 782.2,
- total: 14000,
- },
- {
- name: "RAM",
- value: 5100,
- total: 14000,
- },
- {
- name: "STORAGE",
- value: 500000,
- total: 1000000,
- },
- ];
- return (
-
-
-
-
- Welcome,
-
- let’s download your first model
-
-
-
-
- System status
- {system.map((item, index) => (
-
- ))}
-
-
- );
-};
-
-export default Welcome;
diff --git a/app/app/_helpers/EventListenerWrapper.tsx b/app/app/_helpers/EventListenerWrapper.tsx
deleted file mode 100644
index 7efe04b23..000000000
--- a/app/app/_helpers/EventListenerWrapper.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-// @ts-nocheck
-"use client";
-
-import { useSetAtom } from "jotai";
-import { ReactNode, useEffect } from "react";
-import { modelDownloadStateAtom } from "./JotaiWrapper";
-
-type Props = {
- children: ReactNode;
-};
-
-export default function EventListenerWrapper({ children }: Props) {
- const setDownloadState = useSetAtom(modelDownloadStateAtom);
- useEffect(() => {
- window.electronAPI.onModelDownloadUpdate((event, state) => {
- setDownloadState(state);
- });
-
- window.electronAPI.onModelDownloadError(() => {
- // TODO: Show error message
- });
- }, []);
-
- return {children}
;
-}
diff --git a/app/electron/core/base-plugin/index.js b/app/electron/core/base-plugin/index.js
deleted file mode 100644
index a4a9e8345..000000000
--- a/app/electron/core/base-plugin/index.js
+++ /dev/null
@@ -1,72 +0,0 @@
-const inference = async (prompt) =>
- new Promise(async (resolve) => {
- if (window.electronAPI) {
- const response = await window.electronAPI.sendInquiry(prompt);
- resolve(response);
- }
- });
-
-async function testInference(e) {
- e.preventDefault();
- const message = new FormData(e.target).get("message");
- const resp = await inference(message);
- alert(resp);
-}
-
-const getButton = (text, func) => {
- var element = document.createElement("button");
- element.innerText = text;
- // Add styles to the button element
- element.style.marginTop = "5px";
- element.style.marginRight = "5px";
- element.style.borderRadius = "0.375rem"; // Rounded-md
- element.style.backgroundColor = "rgb(79, 70, 229)"; // bg-indigo-600
- element.style.paddingLeft = "0.875rem"; //
- element.style.paddingRight = "0.875rem"; //
- element.style.fontSize = "0.875rem"; // text-sm
- element.style.fontWeight = "600"; // font-semibold
- element.style.color = "white"; // text-white
- element.style.height = "40px";
- element.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.1)"; // shadow-sm
- element.addEventListener("click", func);
- return element;
-};
-
-const experimentComponent = () => {
- var parent = document.createElement("div");
- const label = document.createElement("p");
- label.style.marginTop = "5px";
- label.innerText = "Inference Plugin";
- parent.appendChild(label);
-
- const form = document.createElement("form");
- form.id = "test";
- form.style.display = "flex"; // Enable Flexbox
- form.style.alignItems = "center"; // Center items horizontally
- form.addEventListener("submit", testInference);
- const input = document.createElement("input");
- input.style.borderRadius = "5px";
- input.style.borderColor = "#E5E7EB";
- input.style.marginTop = "5px";
- input.style.marginRight = "5px";
- input.name = "message";
- form.appendChild(input);
- const button = getButton("Test Inference", null);
- button.type = "submit";
- button.innerText = "Test Inference";
- form.appendChild(button);
-
- parent.appendChild(form);
- return parent;
-};
-
-// Register all the above functions and objects with the relevant extension points
-export function init({ register }) {
- register("inference", "inference", inference);
- // Experiment UI - for Preferences
- register(
- "experimentComponent",
- "base-plugin-experiment-component",
- experimentComponent
- );
-}
diff --git a/app/electron/core/base-plugin/package-lock.json b/app/electron/core/base-plugin/package-lock.json
deleted file mode 100644
index 5f22d4947..000000000
--- a/app/electron/core/base-plugin/package-lock.json
+++ /dev/null
@@ -1,1455 +0,0 @@
-{
- "name": "base-plugin",
- "version": "2.1.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "base-plugin",
- "version": "2.1.0",
- "license": "MIT",
- "devDependencies": {
- "rimraf": "^3.0.2",
- "webpack": "^5.88.2",
- "webpack-cli": "^5.1.4"
- }
- },
- "node_modules/@discoveryjs/json-ext": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
- "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
- "dev": true,
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
- "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/set-array": "^1.0.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/resolve-uri": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
- "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true,
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/source-map": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
- "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
- "dev": true,
- "dependencies": {
- "@jridgewell/gen-mapping": "^0.3.0",
- "@jridgewell/trace-mapping": "^0.3.9"
- }
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
- "dev": true
- },
- "node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.19",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
- "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
- "dev": true,
- "dependencies": {
- "@jridgewell/resolve-uri": "^3.1.0",
- "@jridgewell/sourcemap-codec": "^1.4.14"
- }
- },
- "node_modules/@types/eslint": {
- "version": "8.44.2",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz",
- "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==",
- "dev": true,
- "dependencies": {
- "@types/estree": "*",
- "@types/json-schema": "*"
- }
- },
- "node_modules/@types/eslint-scope": {
- "version": "3.7.4",
- "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
- "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
- "dev": true,
- "dependencies": {
- "@types/eslint": "*",
- "@types/estree": "*"
- }
- },
- "node_modules/@types/estree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
- "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
- "dev": true
- },
- "node_modules/@types/json-schema": {
- "version": "7.0.13",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz",
- "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==",
- "dev": true
- },
- "node_modules/@types/node": {
- "version": "20.6.2",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz",
- "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==",
- "dev": true
- },
- "node_modules/@webassemblyjs/ast": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
- "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/helper-numbers": "1.11.6",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
- }
- },
- "node_modules/@webassemblyjs/floating-point-hex-parser": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
- "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-api-error": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
- "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-buffer": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
- "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-numbers": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
- "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/floating-point-hex-parser": "1.11.6",
- "@webassemblyjs/helper-api-error": "1.11.6",
- "@xtuc/long": "4.2.2"
- }
- },
- "node_modules/@webassemblyjs/helper-wasm-bytecode": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
- "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
- "dev": true
- },
- "node_modules/@webassemblyjs/helper-wasm-section": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
- "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-buffer": "1.11.6",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.11.6"
- }
- },
- "node_modules/@webassemblyjs/ieee754": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
- "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
- "dev": true,
- "dependencies": {
- "@xtuc/ieee754": "^1.2.0"
- }
- },
- "node_modules/@webassemblyjs/leb128": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
- "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
- "dev": true,
- "dependencies": {
- "@xtuc/long": "4.2.2"
- }
- },
- "node_modules/@webassemblyjs/utf8": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
- "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
- "dev": true
- },
- "node_modules/@webassemblyjs/wasm-edit": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
- "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-buffer": "1.11.6",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/helper-wasm-section": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.11.6",
- "@webassemblyjs/wasm-opt": "1.11.6",
- "@webassemblyjs/wasm-parser": "1.11.6",
- "@webassemblyjs/wast-printer": "1.11.6"
- }
- },
- "node_modules/@webassemblyjs/wasm-gen": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
- "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/ieee754": "1.11.6",
- "@webassemblyjs/leb128": "1.11.6",
- "@webassemblyjs/utf8": "1.11.6"
- }
- },
- "node_modules/@webassemblyjs/wasm-opt": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
- "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-buffer": "1.11.6",
- "@webassemblyjs/wasm-gen": "1.11.6",
- "@webassemblyjs/wasm-parser": "1.11.6"
- }
- },
- "node_modules/@webassemblyjs/wasm-parser": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
- "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@webassemblyjs/helper-api-error": "1.11.6",
- "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
- "@webassemblyjs/ieee754": "1.11.6",
- "@webassemblyjs/leb128": "1.11.6",
- "@webassemblyjs/utf8": "1.11.6"
- }
- },
- "node_modules/@webassemblyjs/wast-printer": {
- "version": "1.11.6",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
- "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
- "dev": true,
- "dependencies": {
- "@webassemblyjs/ast": "1.11.6",
- "@xtuc/long": "4.2.2"
- }
- },
- "node_modules/@webpack-cli/configtest": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
- "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==",
- "dev": true,
- "engines": {
- "node": ">=14.15.0"
- },
- "peerDependencies": {
- "webpack": "5.x.x",
- "webpack-cli": "5.x.x"
- }
- },
- "node_modules/@webpack-cli/info": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz",
- "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==",
- "dev": true,
- "engines": {
- "node": ">=14.15.0"
- },
- "peerDependencies": {
- "webpack": "5.x.x",
- "webpack-cli": "5.x.x"
- }
- },
- "node_modules/@webpack-cli/serve": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz",
- "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==",
- "dev": true,
- "engines": {
- "node": ">=14.15.0"
- },
- "peerDependencies": {
- "webpack": "5.x.x",
- "webpack-cli": "5.x.x"
- },
- "peerDependenciesMeta": {
- "webpack-dev-server": {
- "optional": true
- }
- }
- },
- "node_modules/@xtuc/ieee754": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
- "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
- "dev": true
- },
- "node_modules/@xtuc/long": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
- "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
- "dev": true
- },
- "node_modules/acorn": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-import-assertions": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
- "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^8"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ajv-keywords": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
- "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true,
- "peerDependencies": {
- "ajv": "^6.9.1"
- }
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/browserslist": {
- "version": "4.21.10",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
- "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "caniuse-lite": "^1.0.30001517",
- "electron-to-chromium": "^1.4.477",
- "node-releases": "^2.0.13",
- "update-browserslist-db": "^1.0.11"
- },
- "bin": {
- "browserslist": "cli.js"
- },
- "engines": {
- "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
- }
- },
- "node_modules/buffer-from": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
- "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
- "dev": true
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001535",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz",
- "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ]
- },
- "node_modules/chrome-trace-event": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
- "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
- "dev": true,
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/clone-deep": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
- "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
- "dev": true,
- "dependencies": {
- "is-plain-object": "^2.0.4",
- "kind-of": "^6.0.2",
- "shallow-clone": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/colorette": {
- "version": "2.0.20",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
- "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
- "dev": true
- },
- "node_modules/commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
- "dev": true
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/electron-to-chromium": {
- "version": "1.4.523",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz",
- "integrity": "sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg==",
- "dev": true
- },
- "node_modules/enhanced-resolve": {
- "version": "5.15.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
- "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/envinfo": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz",
- "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==",
- "dev": true,
- "bin": {
- "envinfo": "dist/cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/es-module-lexer": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz",
- "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==",
- "dev": true
- },
- "node_modules/escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esrecurse/node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/events": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
- "dev": true,
- "engines": {
- "node": ">=0.8.x"
- }
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "node_modules/fastest-levenshtein": {
- "version": "1.0.16",
- "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
- "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
- "dev": true,
- "engines": {
- "node": ">= 4.9.1"
- }
- },
- "node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/glob-to-regexp": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
- "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
- "dev": true
- },
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/import-local": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
- "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
- "dev": true,
- "dependencies": {
- "pkg-dir": "^4.2.0",
- "resolve-cwd": "^3.0.0"
- },
- "bin": {
- "import-local-fixture": "fixtures/cli.js"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "node_modules/interpret": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
- "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
- "dev": true,
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
- "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
- "dev": true,
- "dependencies": {
- "has": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dev": true,
- "dependencies": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
- "dev": true
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "node_modules/kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/loader-runner": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
- "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
- "dev": true,
- "engines": {
- "node": ">=6.11.5"
- }
- },
- "node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
- "dev": true
- },
- "node_modules/node-releases": {
- "version": "2.0.13",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
- "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
- "dev": true
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
- },
- "node_modules/pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "dependencies": {
- "find-up": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "^5.1.0"
- }
- },
- "node_modules/rechoir": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
- "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
- "dev": true,
- "dependencies": {
- "resolve": "^1.20.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/resolve": {
- "version": "1.22.6",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
- "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-cwd": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
- "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
- "dev": true,
- "dependencies": {
- "resolve-from": "^5.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/schema-utils": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
- "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
- "dev": true,
- "dependencies": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- },
- "engines": {
- "node": ">= 10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- }
- },
- "node_modules/serialize-javascript": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
- "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
- "dev": true,
- "dependencies": {
- "randombytes": "^2.1.0"
- }
- },
- "node_modules/shallow-clone": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
- "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
- "dev": true,
- "dependencies": {
- "kind-of": "^6.0.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/source-map-support": {
- "version": "0.5.21",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
- "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
- "dev": true,
- "dependencies": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/terser": {
- "version": "5.19.4",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.4.tgz",
- "integrity": "sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==",
- "dev": true,
- "dependencies": {
- "@jridgewell/source-map": "^0.3.3",
- "acorn": "^8.8.2",
- "commander": "^2.20.0",
- "source-map-support": "~0.5.20"
- },
- "bin": {
- "terser": "bin/terser"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/terser-webpack-plugin": {
- "version": "5.3.9",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz",
- "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==",
- "dev": true,
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.17",
- "jest-worker": "^27.4.5",
- "schema-utils": "^3.1.1",
- "serialize-javascript": "^6.0.1",
- "terser": "^5.16.8"
- },
- "engines": {
- "node": ">= 10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- },
- "peerDependencies": {
- "webpack": "^5.1.0"
- },
- "peerDependenciesMeta": {
- "@swc/core": {
- "optional": true
- },
- "esbuild": {
- "optional": true
- },
- "uglify-js": {
- "optional": true
- }
- }
- },
- "node_modules/update-browserslist-db": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
- "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/browserslist"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
- },
- "bin": {
- "update-browserslist-db": "cli.js"
- },
- "peerDependencies": {
- "browserslist": ">= 4.21.0"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/watchpack": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
- "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
- "dev": true,
- "dependencies": {
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.1.2"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/webpack": {
- "version": "5.88.2",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz",
- "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==",
- "dev": true,
- "dependencies": {
- "@types/eslint-scope": "^3.7.3",
- "@types/estree": "^1.0.0",
- "@webassemblyjs/ast": "^1.11.5",
- "@webassemblyjs/wasm-edit": "^1.11.5",
- "@webassemblyjs/wasm-parser": "^1.11.5",
- "acorn": "^8.7.1",
- "acorn-import-assertions": "^1.9.0",
- "browserslist": "^4.14.5",
- "chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^5.15.0",
- "es-module-lexer": "^1.2.1",
- "eslint-scope": "5.1.1",
- "events": "^3.2.0",
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.2.9",
- "json-parse-even-better-errors": "^2.3.1",
- "loader-runner": "^4.2.0",
- "mime-types": "^2.1.27",
- "neo-async": "^2.6.2",
- "schema-utils": "^3.2.0",
- "tapable": "^2.1.1",
- "terser-webpack-plugin": "^5.3.7",
- "watchpack": "^2.4.0",
- "webpack-sources": "^3.2.3"
- },
- "bin": {
- "webpack": "bin/webpack.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- },
- "peerDependenciesMeta": {
- "webpack-cli": {
- "optional": true
- }
- }
- },
- "node_modules/webpack-cli": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
- "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
- "dev": true,
- "dependencies": {
- "@discoveryjs/json-ext": "^0.5.0",
- "@webpack-cli/configtest": "^2.1.1",
- "@webpack-cli/info": "^2.0.2",
- "@webpack-cli/serve": "^2.0.5",
- "colorette": "^2.0.14",
- "commander": "^10.0.1",
- "cross-spawn": "^7.0.3",
- "envinfo": "^7.7.3",
- "fastest-levenshtein": "^1.0.12",
- "import-local": "^3.0.2",
- "interpret": "^3.1.1",
- "rechoir": "^0.8.0",
- "webpack-merge": "^5.7.3"
- },
- "bin": {
- "webpack-cli": "bin/cli.js"
- },
- "engines": {
- "node": ">=14.15.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/webpack"
- },
- "peerDependencies": {
- "webpack": "5.x.x"
- },
- "peerDependenciesMeta": {
- "@webpack-cli/generators": {
- "optional": true
- },
- "webpack-bundle-analyzer": {
- "optional": true
- },
- "webpack-dev-server": {
- "optional": true
- }
- }
- },
- "node_modules/webpack-cli/node_modules/commander": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
- "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
- "dev": true,
- "engines": {
- "node": ">=14"
- }
- },
- "node_modules/webpack-merge": {
- "version": "5.9.0",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz",
- "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==",
- "dev": true,
- "dependencies": {
- "clone-deep": "^4.0.1",
- "wildcard": "^2.0.0"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/webpack-sources": {
- "version": "3.2.3",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
- "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
- "dev": true,
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/wildcard": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
- "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
- "dev": true
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
- }
- }
-}
diff --git a/app/electron/core/base-plugin/package.json b/app/electron/core/base-plugin/package.json
deleted file mode 100644
index 6b8346e5f..000000000
--- a/app/electron/core/base-plugin/package.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "base-plugin",
- "version": "2.1.0",
- "description": "",
- "main": "dist/bundle.js",
- "author": "Igor Honhoff",
- "license": "MIT",
- "activationPoints": [
- "init"
- ],
- "scripts": {
- "prepare": "webpack --config webpack.config.js",
- "package": "rimraf ./base-plugin*.tgz && npm pack"
- },
- "devDependencies": {
- "rimraf": "^3.0.2",
- "webpack": "^5.88.2",
- "webpack-cli": "^5.1.4"
- },
- "dependencies": {},
- "files": [
- "dist/*",
- "package.json",
- "README.md"
- ]
-}
diff --git a/app/electron/core/data-plugin/index.js b/app/electron/core/data-plugin/index.js
deleted file mode 100644
index c3f23f756..000000000
--- a/app/electron/core/data-plugin/index.js
+++ /dev/null
@@ -1,137 +0,0 @@
-// Provide an async method to manipulate the price provided by the extension point
-const PLUGIN_NAME = "data-plugin";
-
-const getConversations = () =>
- new Promise((resolve) => {
- if (window && window.electronAPI) {
- window.electronAPI
- .invokePluginFunc(PLUGIN_NAME, "getConversations")
- .then((res) => resolve(res));
- } else {
- resolve([]);
- }
- });
-const getConversationMessages = (id) =>
- new Promise((resolve) => {
- if (window && window.electronAPI) {
- window.electronAPI
- .invokePluginFunc(PLUGIN_NAME, "getConversationMessages", id)
- .then((res) => resolve(res));
- } else {
- resolve([]);
- }
- });
-
-const createConversation = (conversation) =>
- new Promise((resolve) => {
- if (window && window.electronAPI) {
- window.electronAPI
- .invokePluginFunc(PLUGIN_NAME, "storeConversation", conversation)
- .then((res) => {
- resolve(res);
- });
- } else {
- resolve("-");
- }
- });
-const createMessage = (message) =>
- new Promise((resolve) => {
- if (window && window.electronAPI) {
- window.electronAPI
- .invokePluginFunc(PLUGIN_NAME, "storeMessage", message)
- .then((res) => resolve(res));
- } else {
- resolve("-");
- }
- });
-
-const deleteConversation = (id) =>
- new Promise((resolve) => {
- if (window && window.electronAPI) {
- window.electronAPI
- .invokePluginFunc(PLUGIN_NAME, "deleteConversation", id)
- .then((res) => {
- resolve(res);
- });
- } else {
- resolve("-");
- }
- });
-
-const setupDb = () => {
- window.electronAPI.invokePluginFunc(PLUGIN_NAME, "init");
-};
-
-const getButton = (text, func) => {
- var element = document.createElement("button");
- element.innerText = text;
- // Add styles to the button element
- element.style.marginTop = "5px";
- element.style.marginRight = "5px";
- element.style.borderRadius = "0.375rem"; // Rounded-md
- element.style.backgroundColor = "rgb(79, 70, 229)"; // bg-indigo-600
- element.style.padding = "0.875rem 1rem"; // px-3.5 py-2.5
- element.style.fontSize = "0.875rem"; // text-sm
- element.style.fontWeight = "600"; // font-semibold
- element.style.color = "white"; // text-white
- element.style.boxShadow = "0 2px 4px rgba(0, 0, 0, 0.1)"; // shadow-sm
- element.addEventListener("click", func);
- return element;
-};
-const experimentComponent = () => {
- var parent = document.createElement("div");
- const label = document.createElement("p");
- label.style.marginTop = "5px";
- label.innerText = "Data Plugin";
- parent.appendChild(label);
- const getConvs = getButton("Get Conversation", async () => {
- // Define the action you want to perform when the button is clicked
- alert(JSON.stringify(await getConversations()));
- });
- const spawnConv = getButton("Spawn Conversation", async () => {
- // Define the action you want to perform when the button is clicked
- const id = await createConversation({
- name: "test",
- model_id: "yolo",
- });
- alert("A new conversation is created: " + id);
- });
- const deleteLastConv = getButton("Delete Last Conversation", async () => {
- // Define the action you want to perform when the button is clicked
- const convs = await getConversations();
- await deleteConversation(convs[convs.length - 1].id);
- alert("Last conversation is deleted");
- });
- const spawnMessage = getButton("Spawn Message", async () => {
- const convs = await getConversations();
- await createMessage({
- name: "",
- conversation_id: convs[0].id,
- message: "yoo",
- user: "user",
- });
- alert("Message is created");
- });
- parent.appendChild(getConvs);
- parent.appendChild(spawnConv);
- parent.appendChild(deleteLastConv);
- parent.appendChild(spawnMessage);
- return parent;
-};
-
-// Register all the above functions and objects with the relevant extension points
-export function init({ register }) {
- setupDb();
- register("getConversations", "getConv", getConversations, 1);
- register("createConversation", "insertConv", createConversation);
- register("deleteConversation", "deleteConv", deleteConversation);
- register("createMessage", "insertMessage", createMessage);
- register("getConversationMessages", "getMessages", getConversationMessages);
-
- // Experiment UI - for Preferences
- register(
- "experimentComponent",
- "data-plugin-experiment-component",
- experimentComponent
- );
-}
diff --git a/app/electron/core/data-plugin/module.js b/app/electron/core/data-plugin/module.js
deleted file mode 100644
index 528be0548..000000000
--- a/app/electron/core/data-plugin/module.js
+++ /dev/null
@@ -1,152 +0,0 @@
-const sqlite3 = require("sqlite3").verbose();
-const path = require("path");
-const { app } = require("electron");
-
-function init() {
- const db = new sqlite3.Database(path.join(app.getPath("userData"), "jan.db"));
-
- db.serialize(() => {
- db.run(
- "CREATE TABLE IF NOT EXISTS models ( id INTEGER PRIMARY KEY, name TEXT, image TEXT, url TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);"
- );
- db.run(
- "CREATE TABLE IF NOT EXISTS conversations ( id INTEGER PRIMARY KEY, name TEXT, model_id INTEGER, image TEXT, message TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);"
- );
- db.run(
- "CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY, name TEXT, conversation_id INTEGER, user TEXT, message TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);"
- );
- });
-
- const stmt = db.prepare(
- "INSERT INTO conversations (name, model_id, image, message) VALUES (?, ?, ?, ?)"
- );
- stmt.finalize();
- db.close();
-}
-function getConversations() {
- return new Promise((res) => {
- const db = new sqlite3.Database(
- path.join(app.getPath("userData"), "jan.db")
- );
-
- db.all(
- "SELECT * FROM conversations ORDER BY created_at DESC",
- (err, row) => {
- res(row);
- }
- );
- db.close();
- });
-}
-function storeConversation(conversation) {
- return new Promise((res) => {
- const db = new sqlite3.Database(
- path.join(app.getPath("userData"), "jan.db")
- );
-
- db.serialize(() => {
- const stmt = db.prepare(
- "INSERT INTO conversations (name, model_id, image, message) VALUES (?, ?, ?, ?)"
- );
- stmt.run(
- conversation.name,
- conversation.model_id,
- conversation.image,
- conversation.message,
- function (err) {
- if (err) {
- // Handle the insertion error here
- console.error(err.message);
- res(undefined);
- return;
- }
- const id = this.lastID;
- console.log(`Record inserted successfully with ID ${id}`);
- res(id);
- return;
- }
- );
- stmt.finalize();
- });
-
- db.close();
- });
-}
-function storeMessage(message) {
- return new Promise((res) => {
- const db = new sqlite3.Database(
- path.join(app.getPath("userData"), "jan.db")
- );
-
- db.serialize(() => {
- const stmt = db.prepare(
- "INSERT INTO messages (name, conversation_id, user, message) VALUES (?, ?, ?, ?)"
- );
- stmt.run(
- message.name,
- message.conversation_id,
- message.user,
- message.message,
- function (err) {
- if (err) {
- // Handle the insertion error here
- console.error(err.message);
- res(undefined);
- return;
- }
- const id = this.lastID;
- console.log(`Record inserted successfully with ID ${id}`);
- res(id);
- return;
- }
- );
- stmt.finalize();
- });
-
- db.close();
- });
-}
-function deleteConversation(id) {
- return new Promise((res) => {
- const db = new sqlite3.Database(
- path.join(app.getPath("userData"), "jan.db")
- );
-
- db.serialize(() => {
- const deleteConv = db.prepare("DELETE FROM conversations WHERE id = ?");
- deleteConv.run(id);
- deleteConv.finalize();
- const deleteMessages = db.prepare(
- "DELETE FROM messages WHERE conversation_id = ?"
- );
- deleteMessages.run(id);
- deleteMessages.finalize();
- res([]);
- });
-
- db.close();
- });
-}
-
-function getConversationMessages(conversation_id) {
- return new Promise((res) => {
- const db = new sqlite3.Database(
- path.join(app.getPath("userData"), "jan.db")
- );
-
- const query = `SELECT * FROM messages WHERE conversation_id = ${conversation_id} ORDER BY created_at DESC`;
- db.all(query, (err, row) => {
- res(row);
- });
- db.close();
- });
-}
-
-module.exports = {
- init,
- getConversations,
- deleteConversation,
- storeConversation,
- storeMessage,
- getConversationMessages,
-};
diff --git a/app/electron/core/data-plugin/package.json b/app/electron/core/data-plugin/package.json
deleted file mode 100644
index 2e0fd352f..000000000
--- a/app/electron/core/data-plugin/package.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "name": "data-plugin",
- "version": "2.1.0",
- "description": "",
- "main": "dist/bundle.js",
- "author": "Igor Honhoff",
- "license": "MIT",
- "activationPoints": [
- "init"
- ],
- "scripts": {
- "prepare": "webpack --config webpack.config.js",
- "package": "rimraf ./data-plugin*.tgz && cp -f module.js ./dist/module.js && npm pack"
- },
- "devDependencies": {
- "rimraf": "^3.0.2",
- "webpack": "^5.88.2",
- "webpack-cli": "^5.1.4"
- },
- "bundledDependencies": [
- "sql.js",
- "sqlite3"
- ],
- "files": [
- "dist/*",
- "package.json",
- "README.md"
- ],
- "dependencies": {
- "sqlite3": "^5.1.6"
- }
-}
diff --git a/app/electron/core/pre-install/base-plugin.tgz b/app/electron/core/pre-install/base-plugin.tgz
deleted file mode 100644
index b53eef030..000000000
Binary files a/app/electron/core/pre-install/base-plugin.tgz and /dev/null differ
diff --git a/app/electron/core/pre-install/data-plugin.tgz b/app/electron/core/pre-install/data-plugin.tgz
deleted file mode 100644
index 90364adab..000000000
Binary files a/app/electron/core/pre-install/data-plugin.tgz and /dev/null differ
diff --git a/app/electron/core/pre-install/model-management-plugin.tgz b/app/electron/core/pre-install/model-management-plugin.tgz
deleted file mode 100644
index 371d9efa5..000000000
Binary files a/app/electron/core/pre-install/model-management-plugin.tgz and /dev/null differ
diff --git a/app/electron/main.ts b/app/electron/main.ts
deleted file mode 100644
index 1d53d6359..000000000
--- a/app/electron/main.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-// @ts-nocheck
-const {
- app,
- BrowserWindow,
- screen: electronScreen,
- dialog,
- ipcMain,
-} = require("electron");
-const isDev = require("electron-is-dev");
-const path = require("path");
-const pe = require("pluggable-electron/main");
-const fs = require("fs");
-const { mkdir, writeFile } = require("fs/promises");
-const { Readable } = require("stream");
-const { finished } = require("stream/promises");
-const request = require("request");
-const progress = require("request-progress");
-
-let modelSession = undefined;
-let modelName = "llama-2-7b-chat.gguf.q4_0.bin";
-
-let window;
-
-const createMainWindow = () => {
- window = new BrowserWindow({
- width: electronScreen.getPrimaryDisplay().workArea.width,
- height: electronScreen.getPrimaryDisplay().workArea.height,
- show: false,
- backgroundColor: "white",
- webPreferences: {
- nodeIntegration: true,
- enableRemoteModule: true,
- preload: path.resolve(app.getAppPath(), "electron/preload.js"),
- },
- });
-
- ipcMain.handle("invokePluginFunc", async (event, plugin, method, ...args) => {
- const plg = pe
- .getStore()
- .getActivePlugins()
- .filter((p) => p.name === plugin)[0];
- const pluginPath = path.join(
- app.getPath("userData"),
- "plugins",
- plg.name,
- "dist/module.js",
- );
- return await import(
- /* webpackIgnore: true */
- pluginPath
- )
- .then((plugin) => {
- if (typeof plugin[method] === "function") {
- return plugin[method](...args);
- } else {
- console.log(plugin[method]);
- console.error(`Function "${method}" does not exist in the module.`);
- }
- })
- .then((res) => {
- return res;
- })
- .catch((err) => console.log(err));
- });
-
- const startURL = isDev
- ? "http://localhost:3000"
- : `file://${path.join(__dirname, "../out/index.html")}`;
-
- window.loadURL(startURL);
-
- window.once("ready-to-show", () => window.show());
- window.on("closed", () => {
- if (process.platform !== "darwin") app.quit();
- });
-
- window.webContents.openDevTools();
-};
-
-app.whenReady().then(() => {
- createMainWindow();
- setupPlugins();
-
- ipcMain.handle("userData", async (event) => {
- return path.resolve(__dirname, "../");
- });
-
- ipcMain.handle("downloadModel", async (event, url) => {
- const userDataPath = app.getPath("userData");
- const destination = path.resolve(userDataPath, modelName);
-
- progress(request(url), {})
- .on("progress", function (state) {
- window.webContents.send("model-download-update", {
- ...state,
- modelId: modelName,
- });
- })
- .on("error", function (err) {
- window.webContents.send("model-download-error", err);
- })
- .on("end", function () {
- app.relaunch();
- app.exit();
- // Do something after request finishes
- })
- .pipe(fs.createWriteStream(destination));
- });
-
- ipcMain.handle("deleteModel", async (event, modelFileName) => {
- const userDataPath = app.getPath("userData");
- const fullPath = path.join(userDataPath, modelFileName);
-
- let result = "NULL";
- fs.unlink(fullPath, function (err) {
- if (err && err.code == "ENOENT") {
- console.info("File doesn't exist, won't remove it.");
- result = "FILE_NOT_EXIST";
- } else if (err) {
- console.error("Error occurred while trying to remove file");
- result = "ERROR";
- } else {
- console.info(`removed`);
- result = "REMOVED";
- }
- });
- console.log(result);
- return result;
- });
-
- // TODO: add options for model configuration
- ipcMain.handle("initModel", async (event, product) => {
- if (!product.fileName) {
- await dialog.showMessageBox({
- message: "Selected model does not have file name..",
- });
-
- return;
- }
-
- console.info(`Initializing model: ${product.name}..`);
- import(
- isDev
- ? "../node_modules/node-llama-cpp/dist/index.js"
- : path.resolve(
- app.getAppPath(),
- "./../../app.asar.unpacked/node_modules/node-llama-cpp/dist/index.js",
- )
- )
- .then(({ LlamaContext, LlamaChatSession, LlamaModel }) => {
- const modelPath = path.join(app.getPath("userData"), product.fileName);
- // TODO: check if file is already there
- const model = new LlamaModel({
- modelPath: modelPath,
- });
- const context = new LlamaContext({ model });
- modelSession = new LlamaChatSession({ context });
- console.info(`Init model ${product.name} successfully!`);
- })
- .catch(async (e) => {
- await dialog.showMessageBox({
- message: "Failed to import LLM module",
- });
- });
- });
-
- ipcMain.handle("getDownloadedModels", async (event) => {
- const userDataPath = app.getPath("userData");
-
- const allBinariesName = [];
- var files = fs.readdirSync(userDataPath);
- for (var i = 0; i < files.length; i++) {
- var filename = path.join(userDataPath, files[i]);
- var stat = fs.lstatSync(filename);
- if (stat.isDirectory()) {
- // ignore
- } else if (filename.endsWith(".bin")) {
- allBinariesName.push(filename);
- }
- }
- return allBinariesName;
- });
-
- ipcMain.handle("sendInquiry", async (event, question) => {
- if (!modelSession) {
- console.error("Model session has not been initialized!");
- return;
- }
- return modelSession.prompt(question);
- });
-
- app.on("activate", () => {
- if (!BrowserWindow.getAllWindows().length) {
- createMainWindow();
- }
- });
-});
-
-app.on("window-all-closed", () => {
- if (process.platform !== "darwin") {
- app.quit();
- }
-});
-
-function setupPlugins() {
- pe.init({
- // Function to check from the main process that user wants to install a plugin
- confirmInstall: async (plugins) => {
- const answer = await dialog.showMessageBox({
- message: `Are you sure you want to install the plugin ${plugins.join(
- ", ",
- )}`,
- buttons: ["Ok", "Cancel"],
- cancelId: 1,
- });
- return answer.response == 0;
- },
- // Path to install plugin to
- pluginsPath: path.join(app.getPath("userData"), "plugins"),
- });
-}
diff --git a/app/electron/preload.js b/app/electron/preload.js
deleted file mode 100644
index 574597e9f..000000000
--- a/app/electron/preload.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/* eslint-disable react-hooks/rules-of-hooks */
-// Make Pluggable Electron's facade available to the renderer on window.plugins
-const useFacade = require("pluggable-electron/facade");
-useFacade();
-
-const { contextBridge, ipcRenderer } = require("electron");
-
-contextBridge.exposeInMainWorld("electronAPI", {
- invokePluginFunc: (plugin, method, ...args) =>
- ipcRenderer.invoke("invokePluginFunc", plugin, method, ...args),
-
- userData: () => ipcRenderer.invoke("userData"),
-
- sendInquiry: (question) => ipcRenderer.invoke("sendInquiry", question),
-
- initModel: (product) => ipcRenderer.invoke("initModel", product),
-
- getDownloadedModels: () => ipcRenderer.invoke("getDownloadedModels"),
-
- getAvailableModels: () => ipcRenderer.invoke("getAvailableModels"),
-
- deleteModel: (path) => ipcRenderer.invoke("deleteModel", path),
-
- downloadModel: (url) => ipcRenderer.invoke("downloadModel", url),
-
- onModelDownloadUpdate: (callback) =>
- ipcRenderer.on("model-download-update", callback),
-
- onModelDownloadError: (callback) =>
- ipcRenderer.on("model-download-error", callback),
-});
diff --git a/app/images/jan-desktop-dev-instruction-1.png b/app/images/jan-desktop-dev-instruction-1.png
deleted file mode 100644
index 5f2e60da7..000000000
Binary files a/app/images/jan-desktop-dev-instruction-1.png and /dev/null differ
diff --git a/app/images/jan-desktop-dev-instruction-2.png b/app/images/jan-desktop-dev-instruction-2.png
deleted file mode 100644
index ea6cb9526..000000000
Binary files a/app/images/jan-desktop-dev-instruction-2.png and /dev/null differ
diff --git a/app/images/jan-desktop-dev-instruction-3.png b/app/images/jan-desktop-dev-instruction-3.png
deleted file mode 100644
index 29f071985..000000000
Binary files a/app/images/jan-desktop-dev-instruction-3.png and /dev/null differ
diff --git a/app/images/jan-desktop-dev-instruction-4.png b/app/images/jan-desktop-dev-instruction-4.png
deleted file mode 100644
index 30524d91a..000000000
Binary files a/app/images/jan-desktop-dev-instruction-4.png and /dev/null differ
diff --git a/app/images/jan-desktop-dev-instruction-5.png b/app/images/jan-desktop-dev-instruction-5.png
deleted file mode 100644
index 88bcf56f0..000000000
Binary files a/app/images/jan-desktop-dev-instruction-5.png and /dev/null differ
diff --git a/app/images/jan-desktop-dev-instruction-6.png b/app/images/jan-desktop-dev-instruction-6.png
deleted file mode 100644
index ba5c1e383..000000000
Binary files a/app/images/jan-desktop-dev-instruction-6.png and /dev/null differ
diff --git a/conf/db/docker_psql_init.sql b/conf/db/docker_psql_init.sql
deleted file mode 100644
index db34e8393..000000000
--- a/conf/db/docker_psql_init.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-CREATE DATABASE "jan-keycloak"
- WITH
- OWNER = postgres
- ENCODING = 'UTF8'
- LC_COLLATE = 'en_US.utf8'
- LC_CTYPE = 'en_US.utf8'
- TABLESPACE = pg_default
- CONNECTION LIMIT = -1;
-
-CREATE DATABASE "jan-hasura-data"
- WITH
- OWNER = postgres
- ENCODING = 'UTF8'
- LC_COLLATE = 'en_US.utf8'
- LC_CTYPE = 'en_US.utf8'
- TABLESPACE = pg_default
- CONNECTION LIMIT = -1;
-
-CREATE DATABASE "jan-hasura-metadata"
- WITH
- OWNER = postgres
- ENCODING = 'UTF8'
- LC_COLLATE = 'en_US.utf8'
- LC_CTYPE = 'en_US.utf8'
- TABLESPACE = pg_default
- CONNECTION LIMIT = -1;
\ No newline at end of file
diff --git a/conf/keycloak_conf/example-realm.json b/conf/keycloak_conf/example-realm.json
deleted file mode 100644
index bc10dac64..000000000
--- a/conf/keycloak_conf/example-realm.json
+++ /dev/null
@@ -1,2311 +0,0 @@
-{
- "id": "d3ebd3d9-2493-4aa2-942b-3118a216b430",
- "realm": "hasura",
- "notBefore": 0,
- "defaultSignatureAlgorithm": "RS256",
- "revokeRefreshToken": false,
- "refreshTokenMaxReuse": 0,
- "accessTokenLifespan": 300,
- "accessTokenLifespanForImplicitFlow": 900,
- "ssoSessionIdleTimeout": 1800,
- "ssoSessionMaxLifespan": 36000,
- "ssoSessionIdleTimeoutRememberMe": 0,
- "ssoSessionMaxLifespanRememberMe": 0,
- "offlineSessionIdleTimeout": 2592000,
- "offlineSessionMaxLifespanEnabled": false,
- "offlineSessionMaxLifespan": 5184000,
- "clientSessionIdleTimeout": 0,
- "clientSessionMaxLifespan": 0,
- "clientOfflineSessionIdleTimeout": 0,
- "clientOfflineSessionMaxLifespan": 0,
- "accessCodeLifespan": 60,
- "accessCodeLifespanUserAction": 300,
- "accessCodeLifespanLogin": 1800,
- "actionTokenGeneratedByAdminLifespan": 43200,
- "actionTokenGeneratedByUserLifespan": 300,
- "oauth2DeviceCodeLifespan": 600,
- "oauth2DevicePollingInterval": 5,
- "enabled": true,
- "sslRequired": "external",
- "registrationAllowed": false,
- "registrationEmailAsUsername": false,
- "rememberMe": false,
- "verifyEmail": false,
- "loginWithEmailAllowed": true,
- "duplicateEmailsAllowed": false,
- "resetPasswordAllowed": false,
- "editUsernameAllowed": false,
- "bruteForceProtected": false,
- "permanentLockout": false,
- "maxFailureWaitSeconds": 900,
- "minimumQuickLoginWaitSeconds": 60,
- "waitIncrementSeconds": 60,
- "quickLoginCheckMilliSeconds": 1000,
- "maxDeltaTimeSeconds": 43200,
- "failureFactor": 30,
- "roles": {
- "realm": [
- {
- "id": "7219280c-2d93-4cb5-9ff9-fa4b639716fd",
- "name": "uma_authorization",
- "description": "${role_uma_authorization}",
- "composite": false,
- "clientRole": false,
- "containerId": "d3ebd3d9-2493-4aa2-942b-3118a216b430",
- "attributes": {}
- },
- {
- "id": "7fb465bc-beae-431b-8a38-06afa8b4c75c",
- "name": "user",
- "description": "",
- "composite": false,
- "clientRole": false,
- "containerId": "d3ebd3d9-2493-4aa2-942b-3118a216b430",
- "attributes": {}
- },
- {
- "id": "b34240e1-92b8-48e9-aaa5-82eecbdcb283",
- "name": "default-roles-hasura",
- "description": "${role_default-roles}",
- "composite": true,
- "composites": {
- "realm": ["offline_access", "uma_authorization"],
- "client": {
- "account": ["manage-account", "view-profile"]
- }
- },
- "clientRole": false,
- "containerId": "d3ebd3d9-2493-4aa2-942b-3118a216b430",
- "attributes": {}
- },
- {
- "id": "3ece9760-6a06-4d75-9efc-27164c8253c8",
- "name": "offline_access",
- "description": "${role_offline-access}",
- "composite": false,
- "clientRole": false,
- "containerId": "d3ebd3d9-2493-4aa2-942b-3118a216b430",
- "attributes": {}
- }
- ],
- "client": {
- "realm-management": [
- {
- "id": "c8c637d4-39a5-4170-8d2f-1aef0a2f9720",
- "name": "query-groups",
- "description": "${role_query-groups}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "e81f684f-c4ff-425e-861d-80507258b321",
- "name": "manage-authorization",
- "description": "${role_manage-authorization}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "88d97cbc-e7e1-4561-ad9c-8cf1161a55a0",
- "name": "query-realms",
- "description": "${role_query-realms}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "67063d5f-8023-4be9-8db2-37f81dfeb90b",
- "name": "view-identity-providers",
- "description": "${role_view-identity-providers}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "024c8120-8208-4ad4-b098-27c7c9d549df",
- "name": "view-realm",
- "description": "${role_view-realm}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "a2fe97c7-b0d2-444f-bdba-efb2bfecda0f",
- "name": "create-client",
- "description": "${role_create-client}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "bc2425ed-2269-431c-81f6-eb4401020952",
- "name": "query-users",
- "description": "${role_query-users}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "a2cb5869-dc32-4373-8a10-71b9132c850e",
- "name": "view-authorization",
- "description": "${role_view-authorization}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "a8b11879-261c-4e4f-8b05-414069988810",
- "name": "manage-identity-providers",
- "description": "${role_manage-identity-providers}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "0810aa4f-a32c-432a-9c16-0374233f17e6",
- "name": "view-clients",
- "description": "${role_view-clients}",
- "composite": true,
- "composites": {
- "client": {
- "realm-management": ["query-clients"]
- }
- },
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "53b48727-828f-406c-aa7e-b0d1c4109d0b",
- "name": "impersonation",
- "description": "${role_impersonation}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "27751c74-74f3-4fbf-b42a-124de7207dc0",
- "name": "manage-clients",
- "description": "${role_manage-clients}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "44c4d09a-8b0e-413e-91a4-c383ef17b345",
- "name": "query-clients",
- "description": "${role_query-clients}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "837d8209-0fbf-406d-a1f4-d3672879fd7c",
- "name": "manage-realm",
- "description": "${role_manage-realm}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "90b904a0-ddf1-4542-902e-f0f0cd4bc23e",
- "name": "manage-users",
- "description": "${role_manage-users}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "49328548-01c4-477e-90e8-5cdec6ede9d2",
- "name": "view-events",
- "description": "${role_view-events}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "5f381d33-4e28-4b50-87be-0cc0e4887e2f",
- "name": "realm-admin",
- "description": "${role_realm-admin}",
- "composite": true,
- "composites": {
- "client": {
- "realm-management": [
- "query-groups",
- "manage-authorization",
- "view-realm",
- "view-identity-providers",
- "query-realms",
- "create-client",
- "view-authorization",
- "query-users",
- "manage-identity-providers",
- "view-clients",
- "impersonation",
- "manage-clients",
- "query-clients",
- "manage-realm",
- "manage-users",
- "view-events",
- "view-users",
- "manage-events"
- ]
- }
- },
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "13b75adb-cf15-4f02-8c1e-b70bf405b692",
- "name": "view-users",
- "description": "${role_view-users}",
- "composite": true,
- "composites": {
- "client": {
- "realm-management": ["query-groups", "query-users"]
- }
- },
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- },
- {
- "id": "b5126b18-1e29-4989-a0ce-3350feb02b42",
- "name": "manage-events",
- "description": "${role_manage-events}",
- "composite": false,
- "clientRole": true,
- "containerId": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "attributes": {}
- }
- ],
- "security-admin-console": [],
- "admin-cli": [],
- "account-console": [],
- "broker": [
- {
- "id": "ba86f97b-0032-465d-b52d-06d0cb1514b5",
- "name": "read-token",
- "description": "${role_read-token}",
- "composite": false,
- "clientRole": true,
- "containerId": "4a3abf8b-7ce0-4eb3-8733-0b76bde3125d",
- "attributes": {}
- }
- ],
- "account": [
- {
- "id": "8107bb62-629a-4c05-a6b3-9ec05db9feab",
- "name": "manage-consent",
- "description": "${role_manage-consent}",
- "composite": true,
- "composites": {
- "client": {
- "account": ["view-consent"]
- }
- },
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- },
- {
- "id": "cb761f1a-f422-4292-9f27-aeca063ae6ad",
- "name": "view-applications",
- "description": "${role_view-applications}",
- "composite": false,
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- },
- {
- "id": "b87631c3-f3bb-4684-825e-53b7b784687d",
- "name": "manage-account",
- "description": "${role_manage-account}",
- "composite": true,
- "composites": {
- "client": {
- "account": ["manage-account-links"]
- }
- },
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- },
- {
- "id": "81a519c5-d106-4b4c-986d-3416537d91b6",
- "name": "view-groups",
- "description": "${role_view-groups}",
- "composite": false,
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- },
- {
- "id": "e563f5f3-e86f-491c-882a-7acc3d84c6f0",
- "name": "view-consent",
- "description": "${role_view-consent}",
- "composite": false,
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- },
- {
- "id": "4434c108-c594-43e9-b8d4-8ded56196cc5",
- "name": "view-profile",
- "description": "${role_view-profile}",
- "composite": false,
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- },
- {
- "id": "c342ec0b-6885-4d8d-b036-1aafdc376c06",
- "name": "delete-account",
- "description": "${role_delete-account}",
- "composite": false,
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- },
- {
- "id": "5c200c4e-fd80-4cd1-8723-562ba7430398",
- "name": "manage-account-links",
- "description": "${role_manage-account-links}",
- "composite": false,
- "clientRole": true,
- "containerId": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "attributes": {}
- }
- ],
- "hasura": [
- {
- "id": "e971ec56-92a0-4c06-a8a2-a35946852ee6",
- "name": "uma_protection",
- "composite": false,
- "clientRole": true,
- "containerId": "4be1cdcc-b0b3-4581-957b-54fa17c0d929",
- "attributes": {}
- },
- {
- "id": "8cbd62f4-daa2-4809-850b-88870e2c70fc",
- "name": "user",
- "description": "",
- "composite": false,
- "clientRole": true,
- "containerId": "4be1cdcc-b0b3-4581-957b-54fa17c0d929",
- "attributes": {}
- }
- ]
- }
- },
- "groups": [],
- "defaultRole": {
- "id": "b34240e1-92b8-48e9-aaa5-82eecbdcb283",
- "name": "default-roles-hasura",
- "description": "${role_default-roles}",
- "composite": true,
- "clientRole": false,
- "containerId": "d3ebd3d9-2493-4aa2-942b-3118a216b430"
- },
- "requiredCredentials": ["password"],
- "otpPolicyType": "totp",
- "otpPolicyAlgorithm": "HmacSHA1",
- "otpPolicyInitialCounter": 0,
- "otpPolicyDigits": 6,
- "otpPolicyLookAheadWindow": 1,
- "otpPolicyPeriod": 30,
- "otpPolicyCodeReusable": false,
- "otpSupportedApplications": [
- "totpAppGoogleName",
- "totpAppMicrosoftAuthenticatorName",
- "totpAppFreeOTPName"
- ],
- "webAuthnPolicyRpEntityName": "keycloak",
- "webAuthnPolicySignatureAlgorithms": ["ES256"],
- "webAuthnPolicyRpId": "",
- "webAuthnPolicyAttestationConveyancePreference": "not specified",
- "webAuthnPolicyAuthenticatorAttachment": "not specified",
- "webAuthnPolicyRequireResidentKey": "not specified",
- "webAuthnPolicyUserVerificationRequirement": "not specified",
- "webAuthnPolicyCreateTimeout": 0,
- "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
- "webAuthnPolicyAcceptableAaguids": [],
- "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
- "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256"],
- "webAuthnPolicyPasswordlessRpId": "",
- "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
- "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
- "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
- "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
- "webAuthnPolicyPasswordlessCreateTimeout": 0,
- "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
- "webAuthnPolicyPasswordlessAcceptableAaguids": [],
- "users": [
- {
- "username": "username",
- "enabled": true,
- "emailVerified": true,
- "credentials": [
- {
- "type": "password",
- "value": "password"
- }
- ],
- "realmRoles": [
- "user",
- "default-roles-hasura"
- ],
- "clientRoles": {
- "hasura": [
- "user"
- ]
- }
- },
- {
- "id": "8728e38e-6b60-44d2-8830-f1e2ad284a02",
- "createdTimestamp": 1692777925764,
- "username": "service-account-hasura",
- "enabled": true,
- "totp": false,
- "emailVerified": false,
- "serviceAccountClientId": "hasura",
- "disableableCredentialTypes": [],
- "requiredActions": [],
- "realmRoles": ["user", "default-roles-hasura"],
- "clientRoles": {
- "hasura": ["uma_protection"]
- },
- "notBefore": 0,
- "groups": []
- }
- ],
- "scopeMappings": [
- {
- "clientScope": "offline_access",
- "roles": ["offline_access"]
- },
- {
- "clientScope": "hasura",
- "roles": ["user"]
- }
- ],
- "clientScopeMappings": {
- "account": [
- {
- "client": "account-console",
- "roles": ["manage-account", "view-groups"]
- }
- ]
- },
- "clients": [
- {
- "id": "ce02d0ff-b633-4d79-8a33-2c8241017d72",
- "clientId": "account",
- "name": "${client_account}",
- "rootUrl": "${authBaseUrl}",
- "baseUrl": "/realms/hasura/account/",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": ["/realms/hasura/account/*"],
- "webOrigins": [],
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": true,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": false,
- "publicClient": true,
- "frontchannelLogout": false,
- "protocol": "openid-connect",
- "attributes": {
- "post.logout.redirect.uris": "+"
- },
- "authenticationFlowBindingOverrides": {},
- "fullScopeAllowed": false,
- "nodeReRegistrationTimeout": 0,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "roles",
- "profile",
- "email"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "id": "101df256-3450-4b5c-8d0f-d29b531e3499",
- "clientId": "account-console",
- "name": "${client_account-console}",
- "rootUrl": "${authBaseUrl}",
- "baseUrl": "/realms/hasura/account/",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": ["/realms/hasura/account/*"],
- "webOrigins": [],
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": true,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": false,
- "publicClient": true,
- "frontchannelLogout": false,
- "protocol": "openid-connect",
- "attributes": {
- "post.logout.redirect.uris": "+",
- "pkce.code.challenge.method": "S256"
- },
- "authenticationFlowBindingOverrides": {},
- "fullScopeAllowed": false,
- "nodeReRegistrationTimeout": 0,
- "protocolMappers": [
- {
- "id": "b06a98d0-6d91-4260-9406-aea123f842dc",
- "name": "audience resolve",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-audience-resolve-mapper",
- "consentRequired": false,
- "config": {}
- }
- ],
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "roles",
- "profile",
- "email"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "id": "db12bda8-7624-46cc-a84f-9c83cf99b370",
- "clientId": "admin-cli",
- "name": "${client_admin-cli}",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": [],
- "webOrigins": [],
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": false,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": true,
- "serviceAccountsEnabled": false,
- "publicClient": true,
- "frontchannelLogout": false,
- "protocol": "openid-connect",
- "attributes": {},
- "authenticationFlowBindingOverrides": {},
- "fullScopeAllowed": false,
- "nodeReRegistrationTimeout": 0,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "roles",
- "profile",
- "email"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "id": "4a3abf8b-7ce0-4eb3-8733-0b76bde3125d",
- "clientId": "broker",
- "name": "${client_broker}",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": [],
- "webOrigins": [],
- "notBefore": 0,
- "bearerOnly": true,
- "consentRequired": false,
- "standardFlowEnabled": true,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": false,
- "publicClient": false,
- "frontchannelLogout": false,
- "protocol": "openid-connect",
- "attributes": {},
- "authenticationFlowBindingOverrides": {},
- "fullScopeAllowed": false,
- "nodeReRegistrationTimeout": 0,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "roles",
- "profile",
- "email"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "id": "4be1cdcc-b0b3-4581-957b-54fa17c0d929",
- "clientId": "hasura",
- "name": "Hasura",
- "description": "",
- "rootUrl": "",
- "adminUrl": "",
- "baseUrl": "",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "secret": "oMtCPAV7diKpE564SBspgKj4HqlKM4Hy",
- "redirectUris": ["http://localhost:3000/*"],
- "webOrigins": ["http://localhost:3000"],
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": true,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": true,
- "serviceAccountsEnabled": true,
- "authorizationServicesEnabled": true,
- "publicClient": false,
- "frontchannelLogout": true,
- "protocol": "openid-connect",
- "attributes": {
- "oidc.ciba.grant.enabled": "false",
- "oauth2.device.authorization.grant.enabled": "false",
- "client.secret.creation.time": "1692777925",
- "backchannel.logout.session.required": "true",
- "backchannel.logout.revoke.offline.tokens": "false"
- },
- "authenticationFlowBindingOverrides": {},
- "fullScopeAllowed": true,
- "nodeReRegistrationTimeout": -1,
- "protocolMappers": [
- {
- "id": "c4016925-f659-455a-9cdb-29bba88327e9",
- "name": "Client ID",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usersessionmodel-note-mapper",
- "consentRequired": false,
- "config": {
- "user.session.note": "client_id",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "client_id",
- "jsonType.label": "String"
- }
- },
- {
- "id": "e80e0f4c-cd0d-4bb8-a1e4-108a49f4d1a7",
- "name": "Client Host",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usersessionmodel-note-mapper",
- "consentRequired": false,
- "config": {
- "user.session.note": "clientHost",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "clientHost",
- "jsonType.label": "String"
- }
- },
- {
- "id": "3cb8ba1a-81f2-42b7-91b0-3fbe29126262",
- "name": "Client IP Address",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usersessionmodel-note-mapper",
- "consentRequired": false,
- "config": {
- "user.session.note": "clientAddress",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "clientAddress",
- "jsonType.label": "String"
- }
- }
- ],
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "roles",
- "profile",
- "hasura",
- "email"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ],
- "authorizationSettings": {
- "allowRemoteResourceManagement": true,
- "policyEnforcementMode": "ENFORCING",
- "resources": [
- {
- "name": "Default Resource",
- "type": "urn:hasura:resources:default",
- "ownerManagedAccess": false,
- "attributes": {},
- "_id": "088f6856-3491-4600-ac5d-0287da57511c",
- "uris": ["/*"]
- }
- ],
- "policies": [
- {
- "id": "f82ec078-33ce-4204-83c9-627a802c0821",
- "name": "Default Policy",
- "description": "A policy that grants access only for users within this realm",
- "type": "role",
- "logic": "POSITIVE",
- "decisionStrategy": "AFFIRMATIVE",
- "config": {
- "roles": "[{\"id\":\"default-roles-hasura\",\"required\":false}]"
- }
- },
- {
- "id": "2cad4a9f-b0f6-4067-98a7-4f42ed5e33ef",
- "name": "Default Permission",
- "description": "A permission that applies to the default resource type",
- "type": "resource",
- "logic": "POSITIVE",
- "decisionStrategy": "UNANIMOUS",
- "config": {
- "defaultResourceType": "urn:hasura:resources:default",
- "applyPolicies": "[\"Default Policy\"]"
- }
- }
- ],
- "scopes": [],
- "decisionStrategy": "UNANIMOUS"
- }
- },
- {
- "id": "5d7dda49-d56d-4c64-8a01-ee5dd5310c81",
- "clientId": "realm-management",
- "name": "${client_realm-management}",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": [],
- "webOrigins": [],
- "notBefore": 0,
- "bearerOnly": true,
- "consentRequired": false,
- "standardFlowEnabled": true,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": false,
- "publicClient": false,
- "frontchannelLogout": false,
- "protocol": "openid-connect",
- "attributes": {},
- "authenticationFlowBindingOverrides": {},
- "fullScopeAllowed": false,
- "nodeReRegistrationTimeout": 0,
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "roles",
- "profile",
- "email"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- },
- {
- "id": "29f3fff6-2a63-4f7b-9474-d2385f0eff32",
- "clientId": "security-admin-console",
- "name": "${client_security-admin-console}",
- "rootUrl": "${authAdminUrl}",
- "baseUrl": "/admin/hasura/console/",
- "surrogateAuthRequired": false,
- "enabled": true,
- "alwaysDisplayInConsole": false,
- "clientAuthenticatorType": "client-secret",
- "redirectUris": ["/admin/hasura/console/*"],
- "webOrigins": ["+"],
- "notBefore": 0,
- "bearerOnly": false,
- "consentRequired": false,
- "standardFlowEnabled": true,
- "implicitFlowEnabled": false,
- "directAccessGrantsEnabled": false,
- "serviceAccountsEnabled": false,
- "publicClient": true,
- "frontchannelLogout": false,
- "protocol": "openid-connect",
- "attributes": {
- "post.logout.redirect.uris": "+",
- "pkce.code.challenge.method": "S256"
- },
- "authenticationFlowBindingOverrides": {},
- "fullScopeAllowed": false,
- "nodeReRegistrationTimeout": 0,
- "protocolMappers": [
- {
- "id": "795b2582-0f87-46ac-8be0-13518ad27445",
- "name": "locale",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "locale",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "locale",
- "jsonType.label": "String"
- }
- }
- ],
- "defaultClientScopes": [
- "web-origins",
- "acr",
- "roles",
- "profile",
- "email"
- ],
- "optionalClientScopes": [
- "address",
- "phone",
- "offline_access",
- "microprofile-jwt"
- ]
- }
- ],
- "clientScopes": [
- {
- "id": "7df17b55-8301-4667-b9f3-41f9520a92cf",
- "name": "offline_access",
- "description": "OpenID Connect built-in scope: offline_access",
- "protocol": "openid-connect",
- "attributes": {
- "consent.screen.text": "${offlineAccessScopeConsentText}",
- "display.on.consent.screen": "true"
- }
- },
- {
- "id": "9cf833ae-3238-4aa3-9a9a-bbb8bc3767e3",
- "name": "roles",
- "description": "OpenID Connect scope for add user roles to the access token",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "false",
- "display.on.consent.screen": "true",
- "consent.screen.text": "${rolesScopeConsentText}"
- },
- "protocolMappers": [
- {
- "id": "8d49f2bc-7ffc-4ee0-ae71-d82623330caf",
- "name": "client roles",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-client-role-mapper",
- "consentRequired": false,
- "config": {
- "user.attribute": "foo",
- "access.token.claim": "true",
- "claim.name": "resource_access.${client_id}.roles",
- "jsonType.label": "String",
- "multivalued": "true"
- }
- },
- {
- "id": "7e1a84a8-47d0-4cd8-ba0f-dc689588b7ec",
- "name": "realm roles",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-realm-role-mapper",
- "consentRequired": false,
- "config": {
- "user.attribute": "foo",
- "access.token.claim": "true",
- "claim.name": "realm_access.roles",
- "jsonType.label": "String",
- "multivalued": "true"
- }
- },
- {
- "id": "807ae7c0-7c18-4d46-b1c6-9d191294bf7b",
- "name": "audience resolve",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-audience-resolve-mapper",
- "consentRequired": false,
- "config": {}
- }
- ]
- },
- {
- "id": "ad8bfcfe-469b-4e72-82ab-2e8b564efc14",
- "name": "acr",
- "description": "OpenID Connect scope for add acr (authentication context class reference) to the token",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "false",
- "display.on.consent.screen": "false"
- },
- "protocolMappers": [
- {
- "id": "96589cee-a8cc-4919-8b60-00a77a34ff87",
- "name": "acr loa level",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-acr-mapper",
- "consentRequired": false,
- "config": {
- "id.token.claim": "true",
- "access.token.claim": "true"
- }
- }
- ]
- },
- {
- "id": "2a8948cb-65cf-4ce4-ae11-fae5d9391fd3",
- "name": "microprofile-jwt",
- "description": "Microprofile - JWT built-in scope",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "false"
- },
- "protocolMappers": [
- {
- "id": "6679f3f8-c764-4cd4-ae63-9da31200e7c5",
- "name": "upn",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "username",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "upn",
- "jsonType.label": "String"
- }
- },
- {
- "id": "09a8bf42-8326-40a5-b1d3-0a65fe6236c3",
- "name": "groups",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-realm-role-mapper",
- "consentRequired": false,
- "config": {
- "multivalued": "true",
- "user.attribute": "foo",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "groups",
- "jsonType.label": "String"
- }
- }
- ]
- },
- {
- "id": "794f2bc0-4b14-4cb3-a7f2-730b2fabc84d",
- "name": "hasura",
- "description": "",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "true",
- "gui.order": "",
- "consent.screen.text": ""
- },
- "protocolMappers": [
- {
- "id": "74c7a728-24a3-480e-bbb9-2129bd2dccb1",
- "name": "x-hasura-default-role",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-hardcoded-claim-mapper",
- "consentRequired": false,
- "config": {
- "claim.value": "user",
- "userinfo.token.claim": "true",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "https://hasura\\.io/jwt/claims.x-hasura-default-role",
- "jsonType.label": "String",
- "access.tokenResponse.claim": "false"
- }
- },
- {
- "id": "b451832d-670a-4e0d-878e-904c2b1598c2",
- "name": "x-hasura-user-id",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-property-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "id",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "https://hasura\\.io/jwt/claims.x-hasura-user-id",
- "jsonType.label": "String"
- }
- },
- {
- "id": "eb62cfc4-ea5f-454a-9c78-384cb5e80373",
- "name": "x-hasura-allowed-roles",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-client-role-mapper",
- "consentRequired": false,
- "config": {
- "multivalued": "true",
- "userinfo.token.claim": "true",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "https://hasura\\.io/jwt/claims.x-hasura-allowed-roles",
- "jsonType.label": "String",
- "usermodel.clientRoleMapping.clientId": "hasura"
- }
- }
- ]
- },
- {
- "id": "8321f73d-4f9e-486e-ae03-cde49fc78bc1",
- "name": "role_list",
- "description": "SAML role list",
- "protocol": "saml",
- "attributes": {
- "consent.screen.text": "${samlRoleListScopeConsentText}",
- "display.on.consent.screen": "true"
- },
- "protocolMappers": [
- {
- "id": "56bb56c7-0237-4263-b858-7f9cdba57a1d",
- "name": "role list",
- "protocol": "saml",
- "protocolMapper": "saml-role-list-mapper",
- "consentRequired": false,
- "config": {
- "single": "false",
- "attribute.nameformat": "Basic",
- "attribute.name": "Role"
- }
- }
- ]
- },
- {
- "id": "c2c39673-f405-4fed-81a5-3bc3aa333b8b",
- "name": "email",
- "description": "OpenID Connect built-in scope: email",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "true",
- "consent.screen.text": "${emailScopeConsentText}"
- },
- "protocolMappers": [
- {
- "id": "01e5705c-f668-476d-8526-7d8851531832",
- "name": "email",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "email",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "email",
- "jsonType.label": "String"
- }
- },
- {
- "id": "66d6d45a-d4ca-4574-bcbe-b26982b4c7f8",
- "name": "email verified",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-property-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "emailVerified",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "email_verified",
- "jsonType.label": "boolean"
- }
- }
- ]
- },
- {
- "id": "f03591f6-3ea2-405b-b47c-6eb797ec5926",
- "name": "profile",
- "description": "OpenID Connect built-in scope: profile",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "true",
- "consent.screen.text": "${profileScopeConsentText}"
- },
- "protocolMappers": [
- {
- "id": "3c61cc63-50f9-4cfb-b45e-422c59161709",
- "name": "full name",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-full-name-mapper",
- "consentRequired": false,
- "config": {
- "id.token.claim": "true",
- "access.token.claim": "true",
- "userinfo.token.claim": "true"
- }
- },
- {
- "id": "2dfbc3d5-81f1-4160-9b0a-c58fd997fe68",
- "name": "picture",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "picture",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "picture",
- "jsonType.label": "String"
- }
- },
- {
- "id": "a5e7f48a-219c-4bca-a491-d54e8788d8be",
- "name": "username",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "username",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "preferred_username",
- "jsonType.label": "String"
- }
- },
- {
- "id": "837efb21-32d2-47e5-8b1c-fdf5d3ea17bc",
- "name": "website",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "website",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "website",
- "jsonType.label": "String"
- }
- },
- {
- "id": "d1200744-27c1-426c-8332-ce4b0c433c50",
- "name": "zoneinfo",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "zoneinfo",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "zoneinfo",
- "jsonType.label": "String"
- }
- },
- {
- "id": "63eae02f-f44b-4fe6-91f2-a16d096c46db",
- "name": "birthdate",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "birthdate",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "birthdate",
- "jsonType.label": "String"
- }
- },
- {
- "id": "5cbb20a8-2947-420d-9a5d-1ce4eb928117",
- "name": "given name",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "firstName",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "given_name",
- "jsonType.label": "String"
- }
- },
- {
- "id": "fdb72b90-48f8-4dcf-be77-e246fc77814c",
- "name": "family name",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "lastName",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "family_name",
- "jsonType.label": "String"
- }
- },
- {
- "id": "a61f7495-5229-48a8-a1d2-0596f13d1c06",
- "name": "nickname",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "nickname",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "nickname",
- "jsonType.label": "String"
- }
- },
- {
- "id": "ac4150b4-0b5f-4187-a81f-21e582fde2b4",
- "name": "profile",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "profile",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "profile",
- "jsonType.label": "String"
- }
- },
- {
- "id": "2f8cf479-e0f5-49a6-a46b-f4708f60840e",
- "name": "middle name",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "middleName",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "middle_name",
- "jsonType.label": "String"
- }
- },
- {
- "id": "2530d28b-3135-442d-aabe-3dcd20d6370c",
- "name": "locale",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "locale",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "locale",
- "jsonType.label": "String"
- }
- },
- {
- "id": "68ca4cca-c6d3-4fa4-8079-ee0c81286577",
- "name": "gender",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "gender",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "gender",
- "jsonType.label": "String"
- }
- },
- {
- "id": "ef95b412-17ff-4ef5-b9e9-8b95f7cc44b3",
- "name": "updated at",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "updatedAt",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "updated_at",
- "jsonType.label": "long"
- }
- }
- ]
- },
- {
- "id": "8b3ba733-fa23-489f-b954-a0b89fba8b54",
- "name": "web-origins",
- "description": "OpenID Connect scope for add allowed web origins to the access token",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "false",
- "display.on.consent.screen": "false",
- "consent.screen.text": ""
- },
- "protocolMappers": [
- {
- "id": "43ee6247-a7fd-4649-8770-5c966a23b831",
- "name": "allowed web origins",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-allowed-origins-mapper",
- "consentRequired": false,
- "config": {}
- }
- ]
- },
- {
- "id": "818f4f96-a63c-4c1d-9251-d999517ede72",
- "name": "address",
- "description": "OpenID Connect built-in scope: address",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "true",
- "consent.screen.text": "${addressScopeConsentText}"
- },
- "protocolMappers": [
- {
- "id": "f9fbf5ed-195e-44f1-a5d3-6bf64919bb2b",
- "name": "address",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-address-mapper",
- "consentRequired": false,
- "config": {
- "user.attribute.formatted": "formatted",
- "user.attribute.country": "country",
- "user.attribute.postal_code": "postal_code",
- "userinfo.token.claim": "true",
- "user.attribute.street": "street",
- "id.token.claim": "true",
- "user.attribute.region": "region",
- "access.token.claim": "true",
- "user.attribute.locality": "locality"
- }
- }
- ]
- },
- {
- "id": "e3f2c7fe-ca50-4b01-b999-098c82beb362",
- "name": "phone",
- "description": "OpenID Connect built-in scope: phone",
- "protocol": "openid-connect",
- "attributes": {
- "include.in.token.scope": "true",
- "display.on.consent.screen": "true",
- "consent.screen.text": "${phoneScopeConsentText}"
- },
- "protocolMappers": [
- {
- "id": "7ae1a4ac-99db-4a27-8f18-f537a8020e4f",
- "name": "phone number",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "phoneNumber",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "phone_number",
- "jsonType.label": "String"
- }
- },
- {
- "id": "edd5d134-b2c1-47d8-9cc5-3558559cf407",
- "name": "phone number verified",
- "protocol": "openid-connect",
- "protocolMapper": "oidc-usermodel-attribute-mapper",
- "consentRequired": false,
- "config": {
- "userinfo.token.claim": "true",
- "user.attribute": "phoneNumberVerified",
- "id.token.claim": "true",
- "access.token.claim": "true",
- "claim.name": "phone_number_verified",
- "jsonType.label": "boolean"
- }
- }
- ]
- }
- ],
- "defaultDefaultClientScopes": [
- "role_list",
- "profile",
- "email",
- "roles",
- "web-origins",
- "acr",
- "hasura"
- ],
- "defaultOptionalClientScopes": [
- "offline_access",
- "address",
- "phone",
- "microprofile-jwt"
- ],
- "browserSecurityHeaders": {
- "contentSecurityPolicyReportOnly": "",
- "xContentTypeOptions": "nosniff",
- "referrerPolicy": "no-referrer",
- "xRobotsTag": "none",
- "xFrameOptions": "SAMEORIGIN",
- "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
- "xXSSProtection": "1; mode=block",
- "strictTransportSecurity": "max-age=31536000; includeSubDomains"
- },
- "smtpServer": {},
- "eventsEnabled": false,
- "eventsListeners": ["jboss-logging"],
- "enabledEventTypes": [],
- "adminEventsEnabled": false,
- "adminEventsDetailsEnabled": false,
- "identityProviders": [],
- "identityProviderMappers": [],
- "components": {
- "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
- {
- "id": "e2254ce7-52d6-4450-aa77-5ba2b40b8e26",
- "name": "Allowed Client Scopes",
- "providerId": "allowed-client-templates",
- "subType": "anonymous",
- "subComponents": {},
- "config": {
- "allow-default-scopes": ["true"]
- }
- },
- {
- "id": "b88f3a6b-b2a8-476d-9433-904ca547f64c",
- "name": "Allowed Protocol Mapper Types",
- "providerId": "allowed-protocol-mappers",
- "subType": "anonymous",
- "subComponents": {},
- "config": {
- "allowed-protocol-mapper-types": [
- "saml-user-attribute-mapper",
- "oidc-usermodel-property-mapper",
- "oidc-sha256-pairwise-sub-mapper",
- "oidc-full-name-mapper",
- "saml-user-property-mapper",
- "saml-role-list-mapper",
- "oidc-usermodel-attribute-mapper",
- "oidc-address-mapper"
- ]
- }
- },
- {
- "id": "d9ba5290-8c0e-4fa7-bf53-afc4fab4ec4b",
- "name": "Allowed Client Scopes",
- "providerId": "allowed-client-templates",
- "subType": "authenticated",
- "subComponents": {},
- "config": {
- "allow-default-scopes": ["true"]
- }
- },
- {
- "id": "1c24034f-5374-4020-b8e2-ba2eb4c0a944",
- "name": "Full Scope Disabled",
- "providerId": "scope",
- "subType": "anonymous",
- "subComponents": {},
- "config": {}
- },
- {
- "id": "e66a399a-317f-42c0-8ec7-9e2ba781a53d",
- "name": "Consent Required",
- "providerId": "consent-required",
- "subType": "anonymous",
- "subComponents": {},
- "config": {}
- },
- {
- "id": "eec0d3e9-e1e2-41c0-8a03-cc5f06c0f77e",
- "name": "Trusted Hosts",
- "providerId": "trusted-hosts",
- "subType": "anonymous",
- "subComponents": {},
- "config": {
- "host-sending-registration-request-must-match": ["true"],
- "client-uris-must-match": ["true"]
- }
- },
- {
- "id": "01f2436b-aa02-4f55-ac64-6132dd6ee375",
- "name": "Allowed Protocol Mapper Types",
- "providerId": "allowed-protocol-mappers",
- "subType": "authenticated",
- "subComponents": {},
- "config": {
- "allowed-protocol-mapper-types": [
- "oidc-usermodel-property-mapper",
- "saml-user-property-mapper",
- "oidc-usermodel-attribute-mapper",
- "saml-user-attribute-mapper",
- "oidc-full-name-mapper",
- "oidc-address-mapper",
- "oidc-sha256-pairwise-sub-mapper",
- "saml-role-list-mapper"
- ]
- }
- },
- {
- "id": "86fe59f0-cb96-4a39-8476-ae092479fb69",
- "name": "Max Clients Limit",
- "providerId": "max-clients",
- "subType": "anonymous",
- "subComponents": {},
- "config": {
- "max-clients": ["200"]
- }
- }
- ],
- "org.keycloak.keys.KeyProvider": [
- {
- "id": "796db70c-b8e9-4efa-b225-91d8cc8099ea",
- "name": "rsa-enc-generated",
- "providerId": "rsa-enc-generated",
- "subComponents": {},
- "config": {
- "priority": ["100"],
- "algorithm": ["RSA-OAEP"]
- }
- },
- {
- "id": "06ed66b9-a1ac-4662-afb4-889d176189b3",
- "name": "hmac-generated",
- "providerId": "hmac-generated",
- "subComponents": {},
- "config": {
- "priority": ["100"],
- "algorithm": ["HS256"]
- }
- },
- {
- "id": "fc8169fe-cb2b-4edb-befa-fa136215a184",
- "name": "aes-generated",
- "providerId": "aes-generated",
- "subComponents": {},
- "config": {
- "priority": ["100"]
- }
- },
- {
- "id": "9c40d8de-d867-4f6a-9637-b99500551f15",
- "name": "rsa-generated",
- "providerId": "rsa-generated",
- "subComponents": {},
- "config": {
- "priority": ["100"]
- }
- }
- ]
- },
- "internationalizationEnabled": false,
- "supportedLocales": [],
- "authenticationFlows": [
- {
- "id": "da3e4aa5-578c-4a70-a0ee-6bd0ac54acd5",
- "alias": "Account verification options",
- "description": "Method with which to verity the existing account",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "idp-email-verification",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "ALTERNATIVE",
- "priority": 20,
- "autheticatorFlow": true,
- "flowAlias": "Verify Existing Account by Re-authentication",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "489875e5-f48e-484a-8a82-d49e8af1834a",
- "alias": "Browser - Conditional OTP",
- "description": "Flow to determine if the OTP is required for the authentication",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "conditional-user-configured",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "auth-otp-form",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "43d1a926-1785-4391-bf16-519da996ab47",
- "alias": "Direct Grant - Conditional OTP",
- "description": "Flow to determine if the OTP is required for the authentication",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "conditional-user-configured",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "direct-grant-validate-otp",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "27d47660-5e77-4732-b781-36e88d2f6baf",
- "alias": "First broker login - Conditional OTP",
- "description": "Flow to determine if the OTP is required for the authentication",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "conditional-user-configured",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "auth-otp-form",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "a7d1c2ef-57c8-4907-b21b-0d2df675c9c0",
- "alias": "Handle Existing Account",
- "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "idp-confirm-link",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": true,
- "flowAlias": "Account verification options",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "5f97b94f-e60d-498e-8874-d719adbcc985",
- "alias": "Reset - Conditional OTP",
- "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "conditional-user-configured",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "reset-otp",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "22b24e38-53ff-4788-ae8a-dcbce66819a7",
- "alias": "User creation or linking",
- "description": "Flow for the existing/non-existing user alternatives",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticatorConfig": "create unique user config",
- "authenticator": "idp-create-user-if-unique",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "ALTERNATIVE",
- "priority": 20,
- "autheticatorFlow": true,
- "flowAlias": "Handle Existing Account",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "aa67bda7-bfc9-4cd2-84a5-22e371e89135",
- "alias": "Verify Existing Account by Re-authentication",
- "description": "Reauthentication of existing account",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "idp-username-password-form",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "CONDITIONAL",
- "priority": 20,
- "autheticatorFlow": true,
- "flowAlias": "First broker login - Conditional OTP",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "f9b90830-656d-4378-bd98-c11d8a20295c",
- "alias": "browser",
- "description": "browser based authentication",
- "providerId": "basic-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "auth-cookie",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "auth-spnego",
- "authenticatorFlow": false,
- "requirement": "DISABLED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "identity-provider-redirector",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 25,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "ALTERNATIVE",
- "priority": 30,
- "autheticatorFlow": true,
- "flowAlias": "forms",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "9b00a800-deea-4b4a-b9cb-530886a7098a",
- "alias": "clients",
- "description": "Base authentication for clients",
- "providerId": "client-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "client-secret",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "client-jwt",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "client-secret-jwt",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 30,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "client-x509",
- "authenticatorFlow": false,
- "requirement": "ALTERNATIVE",
- "priority": 40,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "88c2fd63-c912-4727-8323-63d31333efaf",
- "alias": "direct grant",
- "description": "OpenID Connect Resource Owner Grant",
- "providerId": "basic-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "direct-grant-validate-username",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "direct-grant-validate-password",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "CONDITIONAL",
- "priority": 30,
- "autheticatorFlow": true,
- "flowAlias": "Direct Grant - Conditional OTP",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "12a8d6fe-ad7e-4443-9b40-b8855535def0",
- "alias": "docker auth",
- "description": "Used by Docker clients to authenticate against the IDP",
- "providerId": "basic-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "docker-http-basic-authenticator",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "c64af03f-9326-4689-ad7e-d804b3fe0d60",
- "alias": "first broker login",
- "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
- "providerId": "basic-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticatorConfig": "review profile config",
- "authenticator": "idp-review-profile",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": true,
- "flowAlias": "User creation or linking",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "b0e1e734-a068-4ab1-b643-9ac5e18b54b9",
- "alias": "forms",
- "description": "Username, password, otp and other auth forms.",
- "providerId": "basic-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "auth-username-password-form",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "CONDITIONAL",
- "priority": 20,
- "autheticatorFlow": true,
- "flowAlias": "Browser - Conditional OTP",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "8978b81a-5145-40bf-9a02-4b9f5c2270cf",
- "alias": "registration",
- "description": "registration flow",
- "providerId": "basic-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "registration-page-form",
- "authenticatorFlow": true,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": true,
- "flowAlias": "registration form",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "dd0879d0-a1c7-47dd-8343-5495259359dc",
- "alias": "registration form",
- "description": "registration form",
- "providerId": "form-flow",
- "topLevel": false,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "registration-user-creation",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "registration-profile-action",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 40,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "registration-password-action",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 50,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "registration-recaptcha-action",
- "authenticatorFlow": false,
- "requirement": "DISABLED",
- "priority": 60,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "2b5b0164-695d-406a-831d-de8e0864ba8b",
- "alias": "reset credentials",
- "description": "Reset credentials for a user if they forgot their password or something",
- "providerId": "basic-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "reset-credentials-choose-user",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "reset-credential-email",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 20,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticator": "reset-password",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 30,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- },
- {
- "authenticatorFlow": true,
- "requirement": "CONDITIONAL",
- "priority": 40,
- "autheticatorFlow": true,
- "flowAlias": "Reset - Conditional OTP",
- "userSetupAllowed": false
- }
- ]
- },
- {
- "id": "b26ac227-95e1-4dea-9673-9cf6f72950d7",
- "alias": "saml ecp",
- "description": "SAML ECP Profile Authentication Flow",
- "providerId": "basic-flow",
- "topLevel": true,
- "builtIn": true,
- "authenticationExecutions": [
- {
- "authenticator": "http-basic-authenticator",
- "authenticatorFlow": false,
- "requirement": "REQUIRED",
- "priority": 10,
- "autheticatorFlow": false,
- "userSetupAllowed": false
- }
- ]
- }
- ],
- "authenticatorConfig": [
- {
- "id": "2c59769e-dc23-4813-8ab7-deaa7cde4de5",
- "alias": "create unique user config",
- "config": {
- "require.password.update.after.registration": "false"
- }
- },
- {
- "id": "49f039b3-3d77-43d1-9a32-706285b18e3d",
- "alias": "review profile config",
- "config": {
- "update.profile.on.first.login": "missing"
- }
- }
- ],
- "requiredActions": [
- {
- "alias": "CONFIGURE_TOTP",
- "name": "Configure OTP",
- "providerId": "CONFIGURE_TOTP",
- "enabled": true,
- "defaultAction": false,
- "priority": 10,
- "config": {}
- },
- {
- "alias": "TERMS_AND_CONDITIONS",
- "name": "Terms and Conditions",
- "providerId": "TERMS_AND_CONDITIONS",
- "enabled": false,
- "defaultAction": false,
- "priority": 20,
- "config": {}
- },
- {
- "alias": "UPDATE_PASSWORD",
- "name": "Update Password",
- "providerId": "UPDATE_PASSWORD",
- "enabled": true,
- "defaultAction": false,
- "priority": 30,
- "config": {}
- },
- {
- "alias": "UPDATE_PROFILE",
- "name": "Update Profile",
- "providerId": "UPDATE_PROFILE",
- "enabled": true,
- "defaultAction": false,
- "priority": 40,
- "config": {}
- },
- {
- "alias": "VERIFY_EMAIL",
- "name": "Verify Email",
- "providerId": "VERIFY_EMAIL",
- "enabled": true,
- "defaultAction": false,
- "priority": 50,
- "config": {}
- },
- {
- "alias": "delete_account",
- "name": "Delete Account",
- "providerId": "delete_account",
- "enabled": false,
- "defaultAction": false,
- "priority": 60,
- "config": {}
- },
- {
- "alias": "webauthn-register",
- "name": "Webauthn Register",
- "providerId": "webauthn-register",
- "enabled": true,
- "defaultAction": false,
- "priority": 70,
- "config": {}
- },
- {
- "alias": "webauthn-register-passwordless",
- "name": "Webauthn Register Passwordless",
- "providerId": "webauthn-register-passwordless",
- "enabled": true,
- "defaultAction": false,
- "priority": 80,
- "config": {}
- },
- {
- "alias": "update_user_locale",
- "name": "Update User Locale",
- "providerId": "update_user_locale",
- "enabled": true,
- "defaultAction": false,
- "priority": 1000,
- "config": {}
- }
- ],
- "browserFlow": "browser",
- "registrationFlow": "registration",
- "directGrantFlow": "direct grant",
- "resetCredentialsFlow": "reset credentials",
- "clientAuthenticationFlow": "clients",
- "dockerAuthenticationFlow": "docker auth",
- "attributes": {
- "cibaBackchannelTokenDeliveryMode": "poll",
- "cibaExpiresIn": "120",
- "cibaAuthRequestedUserHint": "login_hint",
- "oauth2DeviceCodeLifespan": "600",
- "oauth2DevicePollingInterval": "5",
- "parRequestUriLifespan": "60",
- "cibaInterval": "5",
- "realmReusableOtpCode": "false"
- },
- "keycloakVersion": "22.0.0",
- "userManagedAccessAllowed": false,
- "clientProfiles": {
- "profiles": []
- },
- "clientPolicies": {
- "policies": []
- }
-}
diff --git a/conf/keycloak_theme/keywind/.DS_Store b/conf/keycloak_theme/keywind/.DS_Store
deleted file mode 100644
index 694ba58ec..000000000
Binary files a/conf/keycloak_theme/keywind/.DS_Store and /dev/null differ
diff --git a/conf/keycloak_theme/keywind/login/assets/icons/arrow-top-right-on-square.ftl b/conf/keycloak_theme/keywind/login/assets/icons/arrow-top-right-on-square.ftl
deleted file mode 100644
index 81c4bf81d..000000000
--- a/conf/keycloak_theme/keywind/login/assets/icons/arrow-top-right-on-square.ftl
+++ /dev/null
@@ -1,7 +0,0 @@
-<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/arrow-top-right-on-square.svg -->
-<#macro kw>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/icons/chevron-down.ftl b/conf/keycloak_theme/keywind/login/assets/icons/chevron-down.ftl
deleted file mode 100644
index 673ef1191..000000000
--- a/conf/keycloak_theme/keywind/login/assets/icons/chevron-down.ftl
+++ /dev/null
@@ -1,6 +0,0 @@
-<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/chevron-down.svg -->
-<#macro kw>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/bitbucket.ftl b/conf/keycloak_theme/keywind/login/assets/providers/bitbucket.ftl
deleted file mode 100644
index 068bc73d8..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/bitbucket.ftl
+++ /dev/null
@@ -1,14 +0,0 @@
-<#-- https://atlassian.design/resources/logo-library -->
-<#macro kw name="Bitbucket">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/discord.ftl b/conf/keycloak_theme/keywind/login/assets/providers/discord.ftl
deleted file mode 100644
index 8ebecaa48..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/discord.ftl
+++ /dev/null
@@ -1,7 +0,0 @@
-<#-- https://discord.com/branding -->
-<#macro kw name="Discord">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/facebook.ftl b/conf/keycloak_theme/keywind/login/assets/providers/facebook.ftl
deleted file mode 100644
index bc692e759..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/facebook.ftl
+++ /dev/null
@@ -1,8 +0,0 @@
-<#-- https://www.facebook.com/brand/resources/facebookapp/logo -->
-<#macro kw name="Facebook">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/github.ftl b/conf/keycloak_theme/keywind/login/assets/providers/github.ftl
deleted file mode 100644
index 9523103c4..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/github.ftl
+++ /dev/null
@@ -1,7 +0,0 @@
-<#-- https://github.com/logos -->
-<#macro kw name="GitHub">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/gitlab.ftl b/conf/keycloak_theme/keywind/login/assets/providers/gitlab.ftl
deleted file mode 100644
index 4acfc132d..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/gitlab.ftl
+++ /dev/null
@@ -1,10 +0,0 @@
-<#-- https://about.gitlab.com/press/press-kit -->
-<#macro kw name="GitLab">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/google.ftl b/conf/keycloak_theme/keywind/login/assets/providers/google.ftl
deleted file mode 100644
index b536cdbb8..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/google.ftl
+++ /dev/null
@@ -1,10 +0,0 @@
-<#-- https://developers.google.com/identity/branding-guidelines -->
-<#macro kw name="Google">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/instagram.ftl b/conf/keycloak_theme/keywind/login/assets/providers/instagram.ftl
deleted file mode 100644
index c4996d880..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/instagram.ftl
+++ /dev/null
@@ -1,35 +0,0 @@
-<#-- https://www.facebook.com/brand/resources/instagram/instagram-brand -->
-<#macro kw name="Instagram">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/linkedin.ftl b/conf/keycloak_theme/keywind/login/assets/providers/linkedin.ftl
deleted file mode 100644
index 944d14335..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/linkedin.ftl
+++ /dev/null
@@ -1,7 +0,0 @@
-<#-- https://brand.linkedin.com/downloads -->
-<#macro kw name="LinkedIn">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/microsoft.ftl b/conf/keycloak_theme/keywind/login/assets/providers/microsoft.ftl
deleted file mode 100644
index 408635b84..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/microsoft.ftl
+++ /dev/null
@@ -1,10 +0,0 @@
-<#-- https://learn.microsoft.com/azure/active-directory/develop/howto-add-branding-in-azure-ad-apps -->
-<#macro kw name="Microsoft">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/oidc.ftl b/conf/keycloak_theme/keywind/login/assets/providers/oidc.ftl
deleted file mode 100644
index f7954ff5e..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/oidc.ftl
+++ /dev/null
@@ -1,9 +0,0 @@
-<#-- https://openid.net/add-openid/logos -->
-<#macro kw name="OpenID">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/openshift.ftl b/conf/keycloak_theme/keywind/login/assets/providers/openshift.ftl
deleted file mode 100644
index e85ddef7e..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/openshift.ftl
+++ /dev/null
@@ -1,11 +0,0 @@
-<#-- https://www.redhat.com/technologies/cloud-computing/openshift -->
-<#macro kw name="Red Hat OpenShift">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/paypal.ftl b/conf/keycloak_theme/keywind/login/assets/providers/paypal.ftl
deleted file mode 100644
index 7946e03cd..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/paypal.ftl
+++ /dev/null
@@ -1,9 +0,0 @@
-<#-- https://www.paypal.com -->
-<#macro kw name="PayPal">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/providers.ftl b/conf/keycloak_theme/keywind/login/assets/providers/providers.ftl
deleted file mode 100644
index b9c55f6c8..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/providers.ftl
+++ /dev/null
@@ -1,79 +0,0 @@
-<#import "./bitbucket.ftl" as bitbucketIcon>
-<#import "./discord.ftl" as discordIcon>
-<#import "./facebook.ftl" as facebookIcon>
-<#import "./github.ftl" as githubIcon>
-<#import "./gitlab.ftl" as gitlabIcon>
-<#import "./google.ftl" as googleIcon>
-<#import "./instagram.ftl" as instagramIcon>
-<#import "./linkedin.ftl" as linkedinIcon>
-<#import "./microsoft.ftl" as microsoftIcon>
-<#import "./oidc.ftl" as oidcIcon>
-<#import "./openshift.ftl" as openshiftIcon>
-<#import "./paypal.ftl" as paypalIcon>
-<#import "./slack.ftl" as slackIcon>
-<#import "./stackoverflow.ftl" as stackoverflowIcon>
-<#import "./twitter.ftl" as twitterIcon>
-
-<#macro bitbucket>
- <@bitbucketIcon.kw />
-#macro>
-
-<#macro discord>
- <@discordIcon.kw />
-#macro>
-
-<#macro facebook>
- <@facebookIcon.kw />
-#macro>
-
-<#macro github>
- <@githubIcon.kw />
-#macro>
-
-<#macro gitlab>
- <@gitlabIcon.kw />
-#macro>
-
-<#macro google>
- <@googleIcon.kw />
-#macro>
-
-<#macro instagram>
- <@instagramIcon.kw />
-#macro>
-
-<#macro linkedin>
- <@linkedinIcon.kw />
-#macro>
-
-<#macro microsoft>
- <@microsoftIcon.kw />
-#macro>
-
-<#macro oidc>
- <@oidcIcon.kw />
-#macro>
-
-<#macro "openshift-v3">
- <@openshiftIcon.kw />
-#macro>
-
-<#macro "openshift-v4">
- <@openshiftIcon.kw />
-#macro>
-
-<#macro paypal>
- <@paypalIcon.kw />
-#macro>
-
-<#macro slack>
- <@slackIcon.kw />
-#macro>
-
-<#macro stackoverflow>
- <@stackoverflowIcon.kw />
-#macro>
-
-<#macro twitter>
- <@twitterIcon.kw />
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/slack.ftl b/conf/keycloak_theme/keywind/login/assets/providers/slack.ftl
deleted file mode 100644
index d4dffe3bb..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/slack.ftl
+++ /dev/null
@@ -1,14 +0,0 @@
-<#-- https://slack.com/media-kit -->
-<#macro kw name="Slack">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/stackoverflow.ftl b/conf/keycloak_theme/keywind/login/assets/providers/stackoverflow.ftl
deleted file mode 100644
index 1ffad8d6a..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/stackoverflow.ftl
+++ /dev/null
@@ -1,8 +0,0 @@
-<#-- https://stackoverflow.design/brand/logo -->
-<#macro kw name="Stack Overflow">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/assets/providers/twitter.ftl b/conf/keycloak_theme/keywind/login/assets/providers/twitter.ftl
deleted file mode 100644
index 2bc7e7e49..000000000
--- a/conf/keycloak_theme/keywind/login/assets/providers/twitter.ftl
+++ /dev/null
@@ -1,7 +0,0 @@
-<#-- https://about.twitter.com/en/who-we-are/brand-toolkit -->
-<#macro kw name="Twitter">
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/alert.ftl b/conf/keycloak_theme/keywind/login/components/atoms/alert.ftl
deleted file mode 100644
index 58e8309f0..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/alert.ftl
+++ /dev/null
@@ -1,22 +0,0 @@
-<#macro kw color="">
- <#switch color>
- <#case "error">
- <#assign colorClass="bg-red-100 text-red-600">
- <#break>
- <#case "info">
- <#assign colorClass="bg-blue-100 text-blue-600">
- <#break>
- <#case "success">
- <#assign colorClass="bg-green-100 text-green-600">
- <#break>
- <#case "warning">
- <#assign colorClass="bg-orange-100 text-orange-600">
- <#break>
- <#default>
- <#assign colorClass="bg-blue-100 text-blue-600">
- #switch>
-
-
- <#nested>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/body.ftl b/conf/keycloak_theme/keywind/login/components/atoms/body.ftl
deleted file mode 100644
index dcc94a06e..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/body.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
-
- <#nested>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/button-group.ftl b/conf/keycloak_theme/keywind/login/components/atoms/button-group.ftl
deleted file mode 100644
index 459120917..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/button-group.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
-
- <#nested>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/button.ftl b/conf/keycloak_theme/keywind/login/components/atoms/button.ftl
deleted file mode 100644
index eeb0af7b7..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/button.ftl
+++ /dev/null
@@ -1,33 +0,0 @@
-<#macro kw color="" component="button" size="" rest...>
- <#switch color>
- <#case "primary">
- <#assign colorClass="bg-primary-600 text-white focus:ring-primary-600 hover:bg-primary-700">
- <#break>
- <#case "secondary">
- <#assign colorClass="bg-secondary-100 text-secondary-600 focus:ring-secondary-600 hover:bg-secondary-200 hover:text-secondary-900">
- <#break>
- <#default>
- <#assign colorClass="bg-primary-600 text-white focus:ring-primary-600 hover:bg-primary-700">
- #switch>
-
- <#switch size>
- <#case "medium">
- <#assign sizeClass="px-4 py-2 text-sm">
- <#break>
- <#case "small">
- <#assign sizeClass="px-2 py-1 text-xs">
- <#break>
- <#default>
- <#assign sizeClass="px-4 py-2 text-sm">
- #switch>
-
- <${component}
- class="${colorClass} ${sizeClass} flex justify-center relative rounded-lg w-full focus:outline-none focus:ring-2 focus:ring-offset-2"
-
- <#list rest as attrName, attrValue>
- ${attrName}="${attrValue}"
- #list>
- >
- <#nested>
- ${component}>
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/card.ftl b/conf/keycloak_theme/keywind/login/components/atoms/card.ftl
deleted file mode 100644
index c1e808df1..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/card.ftl
+++ /dev/null
@@ -1,19 +0,0 @@
-<#macro kw content="" footer="" header="">
-
- <#if header?has_content>
-
- ${header}
-
- #if>
- <#if content?has_content>
-
- ${content}
-
- #if>
- <#if footer?has_content>
-
- ${footer}
-
- #if>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/checkbox.ftl b/conf/keycloak_theme/keywind/login/components/atoms/checkbox.ftl
deleted file mode 100644
index e47fd619a..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/checkbox.ftl
+++ /dev/null
@@ -1,19 +0,0 @@
-<#macro kw checked=false label="" name="" rest...>
-
- checked#if>
-
- class="border-secondary-200 h-4 rounded text-primary-600 w-4 focus:ring-primary-200 focus:ring-opacity-50"
- id="${name}"
- name="${name}"
- type="checkbox"
-
- <#list rest as attrName, attrValue>
- ${attrName}="${attrValue}"
- #list>
- >
-
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/container.ftl b/conf/keycloak_theme/keywind/login/components/atoms/container.ftl
deleted file mode 100644
index 34ead183c..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/container.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
-
- <#nested>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/form.ftl b/conf/keycloak_theme/keywind/login/components/atoms/form.ftl
deleted file mode 100644
index 014bb4f1c..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/form.ftl
+++ /dev/null
@@ -1,11 +0,0 @@
-<#macro kw rest...>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/heading.ftl b/conf/keycloak_theme/keywind/login/components/atoms/heading.ftl
deleted file mode 100644
index 7665c0196..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/heading.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
-
- <#nested>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/input.ftl b/conf/keycloak_theme/keywind/login/components/atoms/input.ftl
deleted file mode 100644
index 01e2897ad..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/input.ftl
+++ /dev/null
@@ -1,37 +0,0 @@
-<#macro
- kw
- autofocus=false
- disabled=false
- invalid=false
- label=""
- message=""
- name=""
- required=true
- rest...
->
-
-
-
autofocus#if>
- <#if disabled>disabled#if>
- <#if required>required#if>
-
- aria-invalid="${invalid?c}"
- class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm"
- id="${name}"
- name="${name}"
- placeholder="${label}"
-
- <#list rest as attrName, attrValue>
- ${attrName}="${attrValue}"
- #list>
- >
- <#if invalid?? && message??>
-
- ${message?no_esc}
-
- #if>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/link.ftl b/conf/keycloak_theme/keywind/login/components/atoms/link.ftl
deleted file mode 100644
index bde766653..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/link.ftl
+++ /dev/null
@@ -1,30 +0,0 @@
-<#macro kw color="" component="a" size="" rest...>
- <#switch color>
- <#case "primary">
- <#assign colorClass="text-primary-600 hover:text-primary-500">
- <#break>
- <#case "secondary">
- <#assign colorClass="text-secondary-600 hover:text-secondary-900">
- <#break>
- <#default>
- <#assign colorClass="text-primary-600 hover:text-primary-500">
- #switch>
-
- <#switch size>
- <#case "small">
- <#assign sizeClass="text-sm">
- <#break>
- <#default>
- <#assign sizeClass="">
- #switch>
-
- <${component}
- class="<#compress>${colorClass} ${sizeClass} inline-flex#compress>"
-
- <#list rest as attrName, attrValue>
- ${attrName}="${attrValue}"
- #list>
- >
- <#nested>
- ${component}>
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/logo.ftl b/conf/keycloak_theme/keywind/login/components/atoms/logo.ftl
deleted file mode 100644
index f166403e6..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/logo.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
-
- <#nested>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/nav.ftl b/conf/keycloak_theme/keywind/login/components/atoms/nav.ftl
deleted file mode 100644
index 81a4abf63..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/nav.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
-
- <#nested>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/atoms/radio.ftl b/conf/keycloak_theme/keywind/login/components/atoms/radio.ftl
deleted file mode 100644
index 5596d5c4b..000000000
--- a/conf/keycloak_theme/keywind/login/components/atoms/radio.ftl
+++ /dev/null
@@ -1,18 +0,0 @@
-<#macro kw checked=false id="" label="" rest...>
-
- checked#if>
-
- class="border-secondary-200 focus:ring-primary-600"
- id="${id}"
- type="radio"
-
- <#list rest as attrName, attrValue>
- ${attrName}="${attrValue}"
- #list>
- >
-
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/molecules/identity-provider.ftl b/conf/keycloak_theme/keywind/login/components/molecules/identity-provider.ftl
deleted file mode 100644
index 50c9c81c7..000000000
--- a/conf/keycloak_theme/keywind/login/components/molecules/identity-provider.ftl
+++ /dev/null
@@ -1,78 +0,0 @@
-<#import "/assets/providers/providers.ftl" as providerIcons>
-
-<#macro kw providers=[]>
-
- ${msg("identity-provider-login-label")}
-
-
- <#list providers as provider>
- <#switch provider.alias>
- <#case "bitbucket">
- <#assign colorClass="hover:bg-provider-bitbucket/10">
- <#break>
- <#case "discord">
- <#assign colorClass="hover:bg-provider-discord/10">
- <#break>
- <#case "facebook">
- <#assign colorClass="hover:bg-provider-facebook/10">
- <#break>
- <#case "github">
- <#assign colorClass="hover:bg-provider-github/10">
- <#break>
- <#case "gitlab">
- <#assign colorClass="hover:bg-provider-gitlab/10">
- <#break>
- <#case "google">
- <#assign colorClass="hover:bg-provider-google/10">
- <#break>
- <#case "instagram">
- <#assign colorClass="hover:bg-provider-instagram/10">
- <#break>
- <#case "linkedin">
- <#assign colorClass="hover:bg-provider-linkedin/10">
- <#break>
- <#case "microsoft">
- <#assign colorClass="hover:bg-provider-microsoft/10">
- <#break>
- <#case "oidc">
- <#assign colorClass="hover:bg-provider-oidc/10">
- <#break>
- <#case "openshift-v3">
- <#assign colorClass="hover:bg-provider-openshift/10">
- <#break>
- <#case "openshift-v4">
- <#assign colorClass="hover:bg-provider-openshift/10">
- <#break>
- <#case "paypal">
- <#assign colorClass="hover:bg-provider-paypal/10">
- <#break>
- <#case "slack">
- <#assign colorClass="hover:bg-provider-slack/10">
- <#break>
- <#case "stackoverflow">
- <#assign colorClass="hover:bg-provider-stackoverflow/10">
- <#break>
- <#case "twitter">
- <#assign colorClass="hover:bg-provider-twitter/10">
- <#break>
- <#default>
- <#assign colorClass="hover:bg-secondary-100">
- #switch>
-
-
- <#if providerIcons[provider.alias]??>
-
- <@providerIcons[provider.alias] />
-
- <#else>
- ${provider.displayName!}
- #if>
-
- #list>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/molecules/locale-provider.ftl b/conf/keycloak_theme/keywind/login/components/molecules/locale-provider.ftl
deleted file mode 100644
index 198e5be10..000000000
--- a/conf/keycloak_theme/keywind/login/components/molecules/locale-provider.ftl
+++ /dev/null
@@ -1,29 +0,0 @@
-<#import "/assets/icons/chevron-down.ftl" as icon>
-<#import "/components/atoms/link.ftl" as link>
-
-<#macro kw currentLocale="" locales=[]>
-
- <@link.kw @click="open = true" color="secondary" component="button" type="button">
-
- ${currentLocale}
- <@icon.kw />
-
- @link.kw>
-
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/components/molecules/username.ftl b/conf/keycloak_theme/keywind/login/components/molecules/username.ftl
deleted file mode 100644
index ba6339389..000000000
--- a/conf/keycloak_theme/keywind/login/components/molecules/username.ftl
+++ /dev/null
@@ -1,15 +0,0 @@
-<#import "/assets/icons/arrow-top-right-on-square.ftl" as icon>
-<#import "/components/atoms/link.ftl" as link>
-
-<#macro kw linkHref="" linkTitle="" name="">
-
- ${name}
- <@link.kw
- color="primary"
- href=linkHref
- title=linkTitle
- >
- <@icon.kw />
- @link.kw>
-
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/document.ftl b/conf/keycloak_theme/keywind/login/document.ftl
deleted file mode 100644
index 188e16a31..000000000
--- a/conf/keycloak_theme/keywind/login/document.ftl
+++ /dev/null
@@ -1,35 +0,0 @@
-<#macro kw script="">
- ${msg("loginTitle", (realm.displayName!""))}
-
-
-
-
-
- <#if properties.meta?has_content>
- <#list properties.meta?split(" ") as meta>
-
- #list>
- #if>
-
- <#if properties.favicons?has_content>
- <#list properties.favicons?split(" ") as favicon>
-
- #list>
- #if>
-
- <#if properties.styles?has_content>
- <#list properties.styles?split(" ") as style>
-
- #list>
- #if>
-
- <#if script?has_content>
-
- #if>
-
- <#if properties.scripts?has_content>
- <#list properties.scripts?split(" ") as script>
-
- #list>
- #if>
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/error.ftl b/conf/keycloak_theme/keywind/login/error.ftl
deleted file mode 100644
index 52af9c1e6..000000000
--- a/conf/keycloak_theme/keywind/login/error.ftl
+++ /dev/null
@@ -1,18 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/alert.ftl" as alert>
-<#import "components/atoms/link.ftl" as link>
-
-<@layout.registrationLayout displayMessage=false; section>
- <#if section="header">
- ${kcSanitize(msg("errorTitle"))?no_esc}
- <#elseif section="form">
- <@alert.kw color="error">${kcSanitize(message.summary)?no_esc}@alert.kw>
- <#if !skipLink??>
- <#if client?? && client.baseUrl?has_content>
- <@link.kw color="secondary" href=client.baseUrl size="small">
- ${kcSanitize(msg("backToApplication"))?no_esc}
- @link.kw>
- #if>
- #if>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/features/labels/totp-device.ftl b/conf/keycloak_theme/keywind/login/features/labels/totp-device.ftl
deleted file mode 100644
index 98ae12f8d..000000000
--- a/conf/keycloak_theme/keywind/login/features/labels/totp-device.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
- <#compress>
- ${msg("loginTotpDeviceName")} <#if totp.otpCredentials?size gte 1>*#if>
- #compress>
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/features/labels/totp.ftl b/conf/keycloak_theme/keywind/login/features/labels/totp.ftl
deleted file mode 100644
index be5158ebe..000000000
--- a/conf/keycloak_theme/keywind/login/features/labels/totp.ftl
+++ /dev/null
@@ -1,5 +0,0 @@
-<#macro kw>
- <#compress>
- ${msg("authenticatorCode")} *
- #compress>
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/features/labels/username.ftl b/conf/keycloak_theme/keywind/login/features/labels/username.ftl
deleted file mode 100644
index 6c01d6b34..000000000
--- a/conf/keycloak_theme/keywind/login/features/labels/username.ftl
+++ /dev/null
@@ -1,11 +0,0 @@
-<#macro kw>
- <#compress>
- <#if !realm.loginWithEmailAllowed>
- ${msg("username")}
- <#elseif !realm.registrationEmailAsUsername>
- ${msg("usernameOrEmail")}
- <#else>
- ${msg("email")}
- #if>
- #compress>
-#macro>
diff --git a/conf/keycloak_theme/keywind/login/login-config-totp.ftl b/conf/keycloak_theme/keywind/login/login-config-totp.ftl
deleted file mode 100644
index e0b64c634..000000000
--- a/conf/keycloak_theme/keywind/login/login-config-totp.ftl
+++ /dev/null
@@ -1,110 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-<#import "components/atoms/link.ftl" as link>
-<#import "features/labels/totp.ftl" as totpLabel>
-<#import "features/labels/totp-device.ftl" as totpDeviceLabel>
-
-<#assign totpLabel><@totpLabel.kw />#assign>
-<#assign totpDeviceLabel><@totpDeviceLabel.kw />#assign>
-
-<@layout.registrationLayout
- displayMessage=!messagesPerField.existsError("totp", "userLabel")
- displayRequiredFields=false
- ;
- section
->
- <#if section="header">
- ${msg("loginTotpTitle")}
- <#elseif section="form">
-
- -
-
${msg("loginTotpStep1")}
-
- <#list totp.supportedApplications as app>
- - ${msg(app)}
- #list>
-
-
- <#if mode?? && mode="manual">
- -
-
${msg("loginTotpManualStep2")}
- ${totp.totpSecretEncoded}
-
- -
- <@link.kw color="primary" href=totp.qrUrl>
- ${msg("loginTotpScanBarcode")}
- @link.kw>
-
- -
-
${msg("loginTotpManualStep3")}
-
- - ${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)}
- - ${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()}
- - ${msg("loginTotpDigits")}: ${totp.policy.digits}
- <#if totp.policy.type="totp">
- - ${msg("loginTotpInterval")}: ${totp.policy.period}
- <#elseif totp.policy.type="hotp">
- - ${msg("loginTotpCounter")}: ${totp.policy.initialCounter}
- #if>
-
-
- <#else>
- -
-
${msg("loginTotpStep2")}
-
- <@link.kw color="primary" href=totp.manualUrl>
- ${msg("loginTotpUnableToScan")}
- @link.kw>
-
- #if>
- - ${msg("loginTotpStep3")}
- - ${msg("loginTotpStep3DeviceName")}
-
- <@form.kw action=url.loginAction method="post">
-
- <#if mode??>
-
- #if>
- <@input.kw
- autocomplete="off"
- autofocus=true
- invalid=messagesPerField.existsError("totp")
- label=totpLabel
- message=kcSanitize(messagesPerField.get("totp"))
- name="totp"
- required=false
- type="text"
- />
- <@input.kw
- autocomplete="off"
- invalid=messagesPerField.existsError("userLabel")
- label=totpDeviceLabel
- message=kcSanitize(messagesPerField.get("userLabel"))
- name="userLabel"
- required=false
- type="text"
- />
- <@buttonGroup.kw>
- <#if isAppInitiatedAction??>
- <@button.kw color="primary" type="submit">
- ${msg("doSubmit")}
- @button.kw>
- <@button.kw color="secondary" name="cancel-aia" type="submit" value="true">
- ${msg("doCancel")}
- @button.kw>
- <#else>
- <@button.kw color="primary" type="submit">
- ${msg("doSubmit")}
- @button.kw>
- #if>
- @buttonGroup.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-idp-link-confirm.ftl b/conf/keycloak_theme/keywind/login/login-idp-link-confirm.ftl
deleted file mode 100644
index 9a2554d51..000000000
--- a/conf/keycloak_theme/keywind/login/login-idp-link-confirm.ftl
+++ /dev/null
@@ -1,18 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/form.ftl" as form>
-
-<@layout.registrationLayout; section>
- <#if section="header">
- ${msg("confirmLinkIdpTitle")}
- <#elseif section="form">
- <@form.kw action=url.loginAction method="post">
- <@button.kw color="primary" name="submitAction" type="submit" value="updateProfile">
- ${msg("confirmLinkIdpReviewProfile")}
- @button.kw>
- <@button.kw color="primary" name="submitAction" type="submit" value="linkAccount">
- ${msg("confirmLinkIdpContinue", idpDisplayName)}
- @button.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-oauth-grant.ftl b/conf/keycloak_theme/keywind/login/login-oauth-grant.ftl
deleted file mode 100644
index aa4173cbf..000000000
--- a/conf/keycloak_theme/keywind/login/login-oauth-grant.ftl
+++ /dev/null
@@ -1,62 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-
-<@layout.registrationLayout; section>
- <#if section="header">
- <#if client.attributes.logoUri??>
-
- #if>
-
- <#if client.name?has_content>
- ${msg("oauthGrantTitle", advancedMsg(client.name))}
- <#else>
- ${msg("oauthGrantTitle", client.clientId)}
- #if>
-
- <#elseif section="form">
- ${msg("oauthGrantRequest")}
-
- <#if oauth.clientScopesRequested??>
- <#list oauth.clientScopesRequested as clientScope>
- -
- <#if !clientScope.dynamicScopeParameter??>
- ${advancedMsg(clientScope.consentScreenText)}
- <#else>
- ${advancedMsg(clientScope.consentScreenText)}: ${clientScope.dynamicScopeParameter}
- #if>
-
- #list>
- #if>
-
- <#if client.attributes.policyUri?? || client.attributes.tosUri??>
-
- <#if client.name?has_content>
- ${msg("oauthGrantInformation",advancedMsg(client.name))}
- <#else>
- ${msg("oauthGrantInformation",client.clientId)}
- #if>
- <#if client.attributes.tosUri??>
- ${msg("oauthGrantReview")}
- ${msg("oauthGrantTos")}
- #if>
- <#if client.attributes.policyUri??>
- ${msg("oauthGrantReview")}
- ${msg("oauthGrantPolicy")}
- #if>
-
- #if>
- <@form.kw action=url.oauthAction method="post">
-
- <@buttonGroup.kw>
- <@button.kw color="primary" name="accept" type="submit">
- ${msg("doYes")}
- @button.kw>
- <@button.kw color="secondary" name="cancel" type="submit">
- ${msg("doNo")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-otp.ftl b/conf/keycloak_theme/keywind/login/login-otp.ftl
deleted file mode 100644
index b1bb3b975..000000000
--- a/conf/keycloak_theme/keywind/login/login-otp.ftl
+++ /dev/null
@@ -1,50 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-<#import "components/atoms/radio.ftl" as radio>
-<#import "features/labels/totp.ftl" as totpLabel>
-
-<#assign totpLabel><@totpLabel.kw />#assign>
-
-<@layout.registrationLayout
- displayMessage=!messagesPerField.existsError("totp")
- ;
- section
->
- <#if section="header">
- ${msg("doLogIn")}
- <#elseif section="form">
- <@form.kw action=url.loginAction method="post">
- <#if otpLogin.userOtpCredentials?size gt 1>
-
- <#list otpLogin.userOtpCredentials as otpCredential>
- <@radio.kw
- checked=(otpCredential.id == otpLogin.selectedCredentialId)
- id="kw-otp-credential-${otpCredential?index}"
- label=otpCredential.userLabel
- name="selectedCredentialId"
- tabindex=otpCredential?index
- value=otpCredential.id
- />
- #list>
-
- #if>
- <@input.kw
- autocomplete="off"
- autofocus=true
- invalid=messagesPerField.existsError("totp")
- label=totpLabel
- message=kcSanitize(messagesPerField.get("totp"))
- name="otp"
- type="text"
- />
- <@buttonGroup.kw>
- <@button.kw color="primary" name="submitAction" type="submit">
- ${msg("doLogIn")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-page-expired.ftl b/conf/keycloak_theme/keywind/login/login-page-expired.ftl
deleted file mode 100644
index 2b6288d94..000000000
--- a/conf/keycloak_theme/keywind/login/login-page-expired.ftl
+++ /dev/null
@@ -1,18 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-
-<@layout.registrationLayout; section>
- <#if section="header">
- ${msg("pageExpiredTitle")}
- <#elseif section="form">
- <@buttonGroup.kw>
- <@button.kw color="primary" component="a" href=url.loginRestartFlowUrl>
- ${msg("doTryAgain")}
- @button.kw>
- <@button.kw color="secondary" component="a" href=url.loginAction>
- ${msg("doContinue")}
- @button.kw>
- @buttonGroup.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-password.ftl b/conf/keycloak_theme/keywind/login/login-password.ftl
deleted file mode 100644
index 54e7d9dca..000000000
--- a/conf/keycloak_theme/keywind/login/login-password.ftl
+++ /dev/null
@@ -1,39 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-<#import "components/atoms/link.ftl" as link>
-
-<@layout.registrationLayout displayMessage=!messagesPerField.existsError("password"); section>
- <#if section="header">
- ${msg("doLogIn")}
- <#elseif section="form">
- <@form.kw
- action=url.loginAction
- method="post"
- onsubmit="login.disabled = true; return true;"
- >
- <@input.kw
- autofocus=true
- invalid=messagesPerField.existsError("password")
- label=msg("password")
- message=kcSanitize(messagesPerField.get("password"))?no_esc
- name="password"
- type="password"
- />
- <#if realm.resetPasswordAllowed>
-
- <@link.kw color="primary" href=url.loginResetCredentialsUrl size="small">
- ${msg("doForgotPassword")}
- @link.kw>
-
- #if>
- <@buttonGroup.kw>
- <@button.kw color="primary" name="login" type="submit">
- ${msg("doLogIn")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-recovery-authn-code-config.ftl b/conf/keycloak_theme/keywind/login/login-recovery-authn-code-config.ftl
deleted file mode 100644
index 186d71080..000000000
--- a/conf/keycloak_theme/keywind/login/login-recovery-authn-code-config.ftl
+++ /dev/null
@@ -1,91 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/alert.ftl" as alert>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/checkbox.ftl" as checkbox>
-<#import "components/atoms/form.ftl" as form>
-
-<@layout.registrationLayout script="dist/recoveryCodes.js"; section>
- <#if section="header">
- ${msg("recovery-code-config-header")}
- <#elseif section="form">
-
- <@alert.kw color="warning">
-
-
${msg("recovery-code-config-warning-title")}
-
${msg("recovery-code-config-warning-message")}
-
- @alert.kw>
-
- <#list recoveryAuthnCodesConfigBean.generatedRecoveryAuthnCodesList as code>
- - ${code[0..3]}-${code[4..7]}-${code[8..]}
- #list>
-
-
- <@button.kw @click="print" color="secondary" size="small" type="button">
- ${msg("recovery-codes-print")}
- @button.kw>
- <@button.kw @click="download" color="secondary" size="small" type="button">
- ${msg("recovery-codes-download")}
- @button.kw>
- <@button.kw @click="copy" color="secondary" size="small" type="button">
- ${msg("recovery-codes-copy")}
- @button.kw>
-
- <@form.kw action=url.loginAction method="post">
-
-
-
- <@checkbox.kw
- label=msg("recovery-codes-confirmation-message")
- name="kcRecoveryCodesConfirmationCheck"
- required="required"
- x\-ref="confirmationCheck"
- />
- <@buttonGroup.kw>
- <#if isAppInitiatedAction??>
- <@button.kw color="primary" type="submit">
- ${msg("recovery-codes-action-complete")}
- @button.kw>
- <@button.kw
- @click="$refs.confirmationCheck.required = false"
- color="secondary"
- name="cancel-aia"
- type="submit"
- value="true"
- >
- ${msg("recovery-codes-action-cancel")}
- @button.kw>
- <#else>
- <@button.kw color="primary" type="submit">
- ${msg("recovery-codes-action-complete")}
- @button.kw>
- #if>
- @buttonGroup.kw>
- @form.kw>
-
- #if>
-@layout.registrationLayout>
-
-
diff --git a/conf/keycloak_theme/keywind/login/login-recovery-authn-code-input.ftl b/conf/keycloak_theme/keywind/login/login-recovery-authn-code-input.ftl
deleted file mode 100644
index a46bcfa09..000000000
--- a/conf/keycloak_theme/keywind/login/login-recovery-authn-code-input.ftl
+++ /dev/null
@@ -1,26 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-
-<@layout.registrationLayout; section>
- <#if section="header">
- ${msg("auth-recovery-code-header")}
- <#elseif section="form">
- <@form.kw action=url.loginAction method="post">
- <@input.kw
- autocomplete="off"
- autofocus=true
- label=msg("auth-recovery-code-prompt", recoveryAuthnCodesInputBean.codeNumber?c)
- name="recoveryCodeInput"
- type="text"
- />
- <@buttonGroup.kw>
- <@button.kw color="primary" name="login" type="submit">
- ${msg("doLogIn")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-reset-password.ftl b/conf/keycloak_theme/keywind/login/login-reset-password.ftl
deleted file mode 100644
index b0516aae8..000000000
--- a/conf/keycloak_theme/keywind/login/login-reset-password.ftl
+++ /dev/null
@@ -1,44 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-<#import "components/atoms/link.ftl" as link>
-<#import "features/labels/username.ftl" as usernameLabel>
-
-<#assign usernameLabel><@usernameLabel.kw />#assign>
-
-<@layout.registrationLayout
- displayInfo=true
- displayMessage=!messagesPerField.existsError("username")
- ;
- section
->
- <#if section="header">
- ${msg("emailForgotTitle")}
- <#elseif section="form">
- <@form.kw action=url.loginAction method="post">
- <@input.kw
- autocomplete=realm.loginWithEmailAllowed?string("email", "username")
- autofocus=true
- invalid=messagesPerField.existsError("username")
- label=usernameLabel
- message=kcSanitize(messagesPerField.get("username"))
- name="username"
- type="text"
- value=(auth?has_content && auth.showUsername())?then(auth.attemptedUsername, '')
- />
- <@buttonGroup.kw>
- <@button.kw color="primary" type="submit">
- ${msg("doSubmit")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- <#elseif section="info">
- ${msg("emailInstruction")}
- <#elseif section="nav">
- <@link.kw color="secondary" href=url.loginUrl size="small">
- ${kcSanitize(msg("backToLogin"))?no_esc}
- @link.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-update-password.ftl b/conf/keycloak_theme/keywind/login/login-update-password.ftl
deleted file mode 100644
index ed82380e2..000000000
--- a/conf/keycloak_theme/keywind/login/login-update-password.ftl
+++ /dev/null
@@ -1,64 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/checkbox.ftl" as checkbox>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-
-<@layout.registrationLayout
- displayMessage=!messagesPerField.existsError("password", "password-confirm")
- ;
- section
->
- <#if section="header">
- ${msg("updatePasswordTitle")}
- <#elseif section="form">
- <@form.kw action=url.loginAction method="post">
-
-
- <@input.kw
- autocomplete="new-password"
- autofocus=true
- invalid=messagesPerField.existsError("password", "password-confirm")
- label=msg("passwordNew")
- name="password-new"
- type="password"
- />
- <@input.kw
- autocomplete="new-password"
- invalid=messagesPerField.existsError("password-confirm")
- label=msg("passwordConfirm")
- message=kcSanitize(messagesPerField.get("password-confirm"))
- name="password-confirm"
- type="password"
- />
- <#if isAppInitiatedAction??>
- <@checkbox.kw
- checked=true
- label=msg("logoutOtherSessions")
- name="logout-sessions"
- value="on"
- />
- #if>
- <@buttonGroup.kw>
- <#if isAppInitiatedAction??>
- <@button.kw color="primary" type="submit">
- ${msg("doSubmit")}
- @button.kw>
- <@button.kw color="secondary" name="cancel-aia" type="submit" value="true">
- ${msg("doCancel")}
- @button.kw>
- <#else>
- <@button.kw color="primary" type="submit">
- ${msg("doSubmit")}
- @button.kw>
- #if>
- @buttonGroup.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-update-profile.ftl b/conf/keycloak_theme/keywind/login/login-update-profile.ftl
deleted file mode 100644
index 306bad944..000000000
--- a/conf/keycloak_theme/keywind/login/login-update-profile.ftl
+++ /dev/null
@@ -1,71 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-
-<@layout.registrationLayout
- displayMessage=!messagesPerField.existsError("email", "firstName", "lastName", "username")
- ;
- section
->
- <#if section="header">
- ${msg("loginProfileTitle")}
- <#elseif section="form">
- <@form.kw action=url.loginAction method="post">
- <#if user.editUsernameAllowed>
- <@input.kw
- autocomplete="username"
- autofocus=true
- invalid=messagesPerField.existsError("username")
- label=msg("username")
- message=kcSanitize(messagesPerField.get("username"))
- name="username"
- type="text"
- value=(user.username)!''
- />
- #if>
- <@input.kw
- autocomplete="email"
- invalid=messagesPerField.existsError("email")
- label=msg("email")
- message=kcSanitize(messagesPerField.get("email"))
- name="email"
- type="email"
- value=(user.email)!''
- />
- <@input.kw
- autocomplete="given-name"
- invalid=messagesPerField.existsError("firstName")
- label=msg("firstName")
- message=kcSanitize(messagesPerField.get("firstName"))
- name="firstName"
- type="text"
- value=(user.firstName)!''
- />
- <@input.kw
- autocomplete="family-name"
- invalid=messagesPerField.existsError("lastName")
- label=msg("lastName")
- message=kcSanitize(messagesPerField.get("lastName"))
- name="lastName"
- type="text"
- value=(user.lastName)!''
- />
- <@buttonGroup.kw>
- <#if isAppInitiatedAction??>
- <@button.kw color="primary" type="submit">
- ${msg("doSubmit")}
- @button.kw>
- <@button.kw color="secondary" name="cancel-aia" type="submit" value="true">
- ${msg("doCancel")}
- @button.kw>
- <#else>
- <@button.kw color="primary" type="submit">
- ${msg("doSubmit")}
- @button.kw>
- #if>
- @buttonGroup.kw>
- @form.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login-username.ftl b/conf/keycloak_theme/keywind/login/login-username.ftl
deleted file mode 100644
index b8064b2da..000000000
--- a/conf/keycloak_theme/keywind/login/login-username.ftl
+++ /dev/null
@@ -1,71 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/checkbox.ftl" as checkbox>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-<#import "components/atoms/link.ftl" as link>
-<#import "components/molecules/identity-provider.ftl" as identityProvider>
-<#import "features/labels/username.ftl" as usernameLabel>
-
-<#assign usernameLabel><@usernameLabel.kw />#assign>
-
-<@layout.registrationLayout
- displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled??
- displayMessage=!messagesPerField.existsError("username")
- ;
- section
->
- <#if section="header">
- ${msg("loginAccountTitle")}
- <#elseif section="form">
- <#if realm.password>
- <@form.kw
- action=url.loginAction
- method="post"
- onsubmit="login.disabled = true; return true;"
- >
- <#if !usernameHidden??>
- <@input.kw
- autocomplete=realm.loginWithEmailAllowed?string("email", "username")
- autofocus=true
- disabled=usernameEditDisabled??
- invalid=messagesPerField.existsError("username")
- label=usernameLabel
- message=kcSanitize(messagesPerField.get("username"))?no_esc
- name="username"
- type="text"
- value=(login.username)!''
- />
- #if>
- <#if realm.rememberMe && !usernameHidden??>
-
- <@checkbox.kw
- checked=login.rememberMe??
- label=msg("rememberMe")
- name="rememberMe"
- />
-
- #if>
- <@buttonGroup.kw>
- <@button.kw color="primary" name="login" type="submit">
- ${msg("doLogIn")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- #if>
- <#elseif section="info">
- <#if realm.password && realm.registrationAllowed && !registrationDisabled??>
-
- ${msg("noAccount")}
- <@link.kw color="primary" href=url.registrationUrl>
- ${msg("doRegister")}
- @link.kw>
-
- #if>
- <#elseif section="socialProviders">
- <#if realm.password && social.providers??>
- <@identityProvider.kw providers=social.providers />
- #if>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/login.ftl b/conf/keycloak_theme/keywind/login/login.ftl
deleted file mode 100644
index 308413817..000000000
--- a/conf/keycloak_theme/keywind/login/login.ftl
+++ /dev/null
@@ -1,88 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/checkbox.ftl" as checkbox>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-<#import "components/atoms/link.ftl" as link>
-<#import "components/molecules/identity-provider.ftl" as identityProvider>
-<#import "features/labels/username.ftl" as usernameLabel>
-
-<#assign usernameLabel><@usernameLabel.kw />#assign>
-
-<@layout.registrationLayout
- displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled??
- displayMessage=!messagesPerField.existsError("username", "password")
- ;
- section
->
- <#if section="header">
- ${msg("loginAccountTitle")}
- <#elseif section="form">
- <#if realm.password>
- <@form.kw
- action=url.loginAction
- method="post"
- onsubmit="login.disabled = true; return true;"
- >
-
- <@input.kw
- autocomplete=realm.loginWithEmailAllowed?string("email", "username")
- autofocus=true
- disabled=usernameEditDisabled??
- invalid=messagesPerField.existsError("username", "password")
- label=usernameLabel
- message=kcSanitize(messagesPerField.getFirstError("username", "password"))
- name="username"
- type="text"
- value=(login.username)!'username'
- />
- <@input.kw
- invalid=messagesPerField.existsError("username", "password")
- label=msg("password")
- name="password"
- type="password"
- value=(login.password)!'password'
- />
- <#if realm.rememberMe && !usernameEditDisabled?? || realm.resetPasswordAllowed>
-
- <#if realm.rememberMe && !usernameEditDisabled??>
- <@checkbox.kw
- checked=login.rememberMe??
- label=msg("rememberMe")
- name="rememberMe"
- />
- #if>
- <#if realm.resetPasswordAllowed>
- <@link.kw color="primary" href=url.loginResetCredentialsUrl size="small">
- ${msg("doForgotPassword")}
- @link.kw>
- #if>
-
- #if>
- <@buttonGroup.kw>
- <@button.kw color="primary" name="login" type="submit">
- ${msg("doLogIn")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- #if>
- <#elseif section="info">
- <#if realm.password && realm.registrationAllowed && !registrationDisabled??>
-
- ${msg("noAccount")}
- <@link.kw color="primary" href=url.registrationUrl>
- ${msg("doRegister")}
- @link.kw>
-
- #if>
- <#elseif section="socialProviders">
- <#if realm.password && social.providers??>
- <@identityProvider.kw providers=social.providers />
- #if>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/logout-confirm.ftl b/conf/keycloak_theme/keywind/login/logout-confirm.ftl
deleted file mode 100644
index e7ec48626..000000000
--- a/conf/keycloak_theme/keywind/login/logout-confirm.ftl
+++ /dev/null
@@ -1,25 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/link.ftl" as link>
-
-<@layout.registrationLayout; section>
- <#if section="header">
- ${msg("logoutConfirmTitle")}
- <#elseif section="form">
- ${msg("logoutConfirmHeader")}
- <@form.kw action=url.logoutConfirmAction method="post">
-
- <@button.kw color="primary" name="confirmLogout" type="submit" value=msg('doLogout')>
- ${msg("doLogout")}
- @button.kw>
- @form.kw>
- <#if !logoutConfirm.skipLink>
- <#if (client.baseUrl)?has_content>
- <@link.kw color="secondary" href=client.baseUrl size="small">
- ${kcSanitize(msg("backToApplication"))?no_esc}
- @link.kw>
- #if>
- #if>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/register.ftl b/conf/keycloak_theme/keywind/login/register.ftl
deleted file mode 100644
index c1a2f061f..000000000
--- a/conf/keycloak_theme/keywind/login/register.ftl
+++ /dev/null
@@ -1,88 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-<#import "components/atoms/form.ftl" as form>
-<#import "components/atoms/input.ftl" as input>
-<#import "components/atoms/link.ftl" as link>
-
-<@layout.registrationLayout
- displayMessage=!messagesPerField.existsError("firstName", "lastName", "email", "username", "password", "password-confirm")
- ;
- section
->
- <#if section="header">
- ${msg("registerTitle")}
- <#elseif section="form">
- <@form.kw action=url.registrationAction method="post">
- <@input.kw
- autocomplete="given-name"
- autofocus=true
- invalid=messagesPerField.existsError("firstName")
- label=msg("firstName")
- message=kcSanitize(messagesPerField.get("firstName"))
- name="firstName"
- type="text"
- value=(register.formData.firstName)!''
- />
- <@input.kw
- autocomplete="family-name"
- invalid=messagesPerField.existsError("lastName")
- label=msg("lastName")
- message=kcSanitize(messagesPerField.get("lastName"))
- name="lastName"
- type="text"
- value=(register.formData.lastName)!''
- />
- <@input.kw
- autocomplete="email"
- invalid=messagesPerField.existsError("email")
- label=msg("email")
- message=kcSanitize(messagesPerField.get("email"))
- name="email"
- type="email"
- value=(register.formData.email)!''
- />
- <#if !realm.registrationEmailAsUsername>
- <@input.kw
- autocomplete="username"
- invalid=messagesPerField.existsError("username")
- label=msg("username")
- message=kcSanitize(messagesPerField.get("username"))
- name="username"
- type="text"
- value=(register.formData.username)!''
- />
- #if>
- <#if passwordRequired??>
- <@input.kw
- autocomplete="new-password"
- invalid=messagesPerField.existsError("password", "password-confirm")
- label=msg("password")
- message=kcSanitize(messagesPerField.getFirstError("password", "password-confirm"))
- name="password"
- type="password"
- />
- <@input.kw
- autocomplete="new-password"
- invalid=messagesPerField.existsError("password-confirm")
- label=msg("passwordConfirm")
- message=kcSanitize(messagesPerField.get("password-confirm"))
- name="password-confirm"
- type="password"
- />
- #if>
- <#if recaptchaRequired??>
-
- #if>
- <@buttonGroup.kw>
- <@button.kw color="primary" type="submit">
- ${msg("doRegister")}
- @button.kw>
- @buttonGroup.kw>
- @form.kw>
- <#elseif section="nav">
- <@link.kw color="secondary" href=url.loginUrl size="small">
- ${kcSanitize(msg("backToLogin"))?no_esc}
- @link.kw>
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/resources/dist/assets/index-a7b84447.js b/conf/keycloak_theme/keywind/login/resources/dist/assets/index-a7b84447.js
deleted file mode 100644
index c1b2f3c66..000000000
--- a/conf/keycloak_theme/keywind/login/resources/dist/assets/index-a7b84447.js
+++ /dev/null
@@ -1 +0,0 @@
-var s={};Object.defineProperty(s,"__esModule",{value:!0});function v(e,r,a){var l;if(a===void 0&&(a={}),!r.codes){r.codes={};for(var n=0;n=8&&(t-=8,c[u++]=255&i>>t)}if(t>=r.bits||255&i<<8-t)throw new SyntaxError("Unexpected end of data");return c}function o(e,r,a){a===void 0&&(a={});for(var l=a,n=l.pad,b=n===void 0?!0:n,c=(1<r.bits;)i-=r.bits,t+=r.chars[c&u>>i];if(i&&(t+=r.chars[c&u<Te&&R.splice(t,1)}function $r(){!Me&&!Ce&&(Ce=!0,queueMicrotask(Rr))}function Rr(){Ce=!1,Me=!0;for(let e=0;ee.effect(t,{scheduler:r=>{Ie?Ir(r):r()}}),yt=e.raw}function ct(e){z=e}function Lr(e){let t=()=>{};return[n=>{let i=z(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),Z(i))},i},()=>{t()}]}var xt=[],bt=[],mt=[];function Fr(e){mt.push(e)}function wt(e,t){typeof t=="function"?(e._x_cleanups||(e._x_cleanups=[]),e._x_cleanups.push(t)):(t=e,bt.push(t))}function Kr(e){xt.push(e)}function Dr(e,t,r){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(r)}function Et(e,t){e._x_attributeCleanups&&Object.entries(e._x_attributeCleanups).forEach(([r,n])=>{(t===void 0||t.includes(r))&&(n.forEach(i=>i()),delete e._x_attributeCleanups[r])})}var qe=new MutationObserver(Je),We=!1;function Ve(){qe.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),We=!0}function St(){Br(),qe.disconnect(),We=!1}var U=[],Ee=!1;function Br(){U=U.concat(qe.takeRecords()),U.length&&!Ee&&(Ee=!0,queueMicrotask(()=>{kr(),Ee=!1}))}function kr(){Je(U),U.length=0}function x(e){if(!We)return e();St();let t=e();return Ve(),t}var Ue=!1,ae=[];function zr(){Ue=!0}function Hr(){Ue=!1,Je(ae),ae=[]}function Je(e){if(Ue){ae=ae.concat(e);return}let t=[],r=[],n=new Map,i=new Map;for(let o=0;os.nodeType===1&&t.push(s)),e[o].removedNodes.forEach(s=>s.nodeType===1&&r.push(s))),e[o].type==="attributes")){let s=e[o].target,a=e[o].attributeName,u=e[o].oldValue,c=()=>{n.has(s)||n.set(s,[]),n.get(s).push({name:a,value:s.getAttribute(a)})},l=()=>{i.has(s)||i.set(s,[]),i.get(s).push(a)};s.hasAttribute(a)&&u===null?c():s.hasAttribute(a)?(l(),c()):l()}i.forEach((o,s)=>{Et(s,o)}),n.forEach((o,s)=>{xt.forEach(a=>a(s,o))});for(let o of r)if(!t.includes(o)&&(bt.forEach(s=>s(o)),o._x_cleanups))for(;o._x_cleanups.length;)o._x_cleanups.pop()();t.forEach(o=>{o._x_ignoreSelf=!0,o._x_ignore=!0});for(let o of t)r.includes(o)||o.isConnected&&(delete o._x_ignoreSelf,delete o._x_ignore,mt.forEach(s=>s(o)),o._x_ignore=!0,o._x_ignoreSelf=!0);t.forEach(o=>{delete o._x_ignoreSelf,delete o._x_ignore}),t=null,r=null,n=null,i=null}function At(e){return ee(K(e))}function X(e,t,r){return e._x_dataStack=[t,...K(r||e)],()=>{e._x_dataStack=e._x_dataStack.filter(n=>n!==t)}}function lt(e,t){let r=e._x_dataStack[0];Object.entries(t).forEach(([n,i])=>{r[n]=i})}function K(e){return e._x_dataStack?e._x_dataStack:typeof ShadowRoot=="function"&&e instanceof ShadowRoot?K(e.host):e.parentNode?K(e.parentNode):[]}function ee(e){let t=new Proxy({},{ownKeys:()=>Array.from(new Set(e.flatMap(r=>Object.keys(r)))),has:(r,n)=>e.some(i=>i.hasOwnProperty(n)),get:(r,n)=>(e.find(i=>{if(i.hasOwnProperty(n)){let o=Object.getOwnPropertyDescriptor(i,n);if(o.get&&o.get._x_alreadyBound||o.set&&o.set._x_alreadyBound)return!0;if((o.get||o.set)&&o.enumerable){let s=o.get,a=o.set,u=o;s=s&&s.bind(t),a=a&&a.bind(t),s&&(s._x_alreadyBound=!0),a&&(a._x_alreadyBound=!0),Object.defineProperty(i,n,{...u,get:s,set:a})}return!0}return!1})||{})[n],set:(r,n,i)=>{let o=e.find(s=>s.hasOwnProperty(n));return o?o[n]=i:e[e.length-1][n]=i,!0}});return t}function Ot(e){let t=n=>typeof n=="object"&&!Array.isArray(n)&&n!==null,r=(n,i="")=>{Object.entries(Object.getOwnPropertyDescriptors(n)).forEach(([o,{value:s,enumerable:a}])=>{if(a===!1||s===void 0)return;let u=i===""?o:`${i}.${o}`;typeof s=="object"&&s!==null&&s._x_interceptor?n[o]=s.initialize(e,u,o):t(s)&&s!==n&&!(s instanceof Element)&&r(s,u)})};return r(e)}function Ct(e,t=()=>{}){let r={initialValue:void 0,_x_interceptor:!0,initialize(n,i,o){return e(this.initialValue,()=>qr(n,i),s=>Pe(n,i,s),i,o)}};return t(r),n=>{if(typeof n=="object"&&n!==null&&n._x_interceptor){let i=r.initialize.bind(r);r.initialize=(o,s,a)=>{let u=n.initialize(o,s,a);return r.initialValue=u,i(o,s,a)}}else r.initialValue=n;return r}}function qr(e,t){return t.split(".").reduce((r,n)=>r[n],e)}function Pe(e,t,r){if(typeof t=="string"&&(t=t.split(".")),t.length===1)e[t[0]]=r;else{if(t.length===0)throw error;return e[t[0]]||(e[t[0]]={}),Pe(e[t[0]],t.slice(1),r)}}var Mt={};function S(e,t){Mt[e]=t}function $e(e,t){return Object.entries(Mt).forEach(([r,n])=>{Object.defineProperty(e,`$${r}`,{get(){let[i,o]=Rt(t);return i={interceptor:Ct,...i},wt(t,o),n(t,i)},enumerable:!1})}),e}function Wr(e,t,r,...n){try{return r(...n)}catch(i){Y(i,e,t)}}function Y(e,t,r=void 0){Object.assign(e,{el:t,expression:r}),console.warn(`Alpine Expression Error: ${e.message}
-
-${r?'Expression: "'+r+`"
-
-`:""}`,t),setTimeout(()=>{throw e},0)}var se=!0;function Vr(e){let t=se;se=!1,e(),se=t}function F(e,t,r={}){let n;return m(e,t)(i=>n=i,r),n}function m(...e){return Tt(...e)}var Tt=It;function Ur(e){Tt=e}function It(e,t){let r={};$e(r,e);let n=[r,...K(e)],i=typeof t=="function"?Jr(n,t):Yr(n,t,e);return Wr.bind(null,e,t,i)}function Jr(e,t){return(r=()=>{},{scope:n={},params:i=[]}={})=>{let o=t.apply(ee([n,...e]),i);ue(r,o)}}var Se={};function Gr(e,t){if(Se[e])return Se[e];let r=Object.getPrototypeOf(async function(){}).constructor,n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(async()=>{ ${e} })()`:e,o=(()=>{try{return new r(["__self","scope"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`)}catch(s){return Y(s,t,e),Promise.resolve()}})();return Se[e]=o,o}function Yr(e,t,r){let n=Gr(t,r);return(i=()=>{},{scope:o={},params:s=[]}={})=>{n.result=void 0,n.finished=!1;let a=ee([o,...e]);if(typeof n=="function"){let u=n(n,a).catch(c=>Y(c,r,t));n.finished?(ue(i,n.result,a,s,r),n.result=void 0):u.then(c=>{ue(i,c,a,s,r)}).catch(c=>Y(c,r,t)).finally(()=>n.result=void 0)}}}function ue(e,t,r,n,i){if(se&&typeof t=="function"){let o=t.apply(r,n);o instanceof Promise?o.then(s=>ue(e,s,r,n)).catch(s=>Y(s,i,t)):e(o)}else typeof t=="object"&&t instanceof Promise?t.then(o=>e(o)):e(t)}var Ge="x-";function H(e=""){return Ge+e}function Qr(e){Ge=e}var Re={};function g(e,t){return Re[e]=t,{before(r){if(!Re[r]){console.warn("Cannot find directive `${directive}`. `${name}` will use the default order of execution");return}const n=$.indexOf(r);$.splice(n>=0?n:$.indexOf("DEFAULT"),0,e)}}}function Ye(e,t,r){if(t=Array.from(t),e._x_virtualDirectives){let o=Object.entries(e._x_virtualDirectives).map(([a,u])=>({name:a,value:u})),s=Pt(o);o=o.map(a=>s.find(u=>u.name===a.name)?{name:`x-bind:${a.name}`,value:`"${a.value}"`}:a),t=t.concat(o)}let n={};return t.map(Lt((o,s)=>n[o]=s)).filter(Kt).map(en(n,r)).sort(tn).map(o=>Xr(e,o))}function Pt(e){return Array.from(e).map(Lt()).filter(t=>!Kt(t))}var je=!1,V=new Map,$t=Symbol();function Zr(e){je=!0;let t=Symbol();$t=t,V.set(t,[]);let r=()=>{for(;V.get(t).length;)V.get(t).shift()();V.delete(t)},n=()=>{je=!1,r()};e(r),n()}function Rt(e){let t=[],r=a=>t.push(a),[n,i]=Lr(e);return t.push(i),[{Alpine:re,effect:n,cleanup:r,evaluateLater:m.bind(m,e),evaluate:F.bind(F,e)},()=>t.forEach(a=>a())]}function Xr(e,t){let r=()=>{},n=Re[t.type]||r,[i,o]=Rt(e);Dr(e,t.original,o);let s=()=>{e._x_ignore||e._x_ignoreSelf||(n.inline&&n.inline(e,t,i),n=n.bind(n,e,t,i),je?V.get($t).push(n):n())};return s.runCleanups=o,s}var jt=(e,t)=>({name:r,value:n})=>(r.startsWith(e)&&(r=r.replace(e,t)),{name:r,value:n}),Nt=e=>e;function Lt(e=()=>{}){return({name:t,value:r})=>{let{name:n,value:i}=Ft.reduce((o,s)=>s(o),{name:t,value:r});return n!==t&&e(n,t),{name:n,value:i}}}var Ft=[];function Qe(e){Ft.push(e)}function Kt({name:e}){return Dt().test(e)}var Dt=()=>new RegExp(`^${Ge}([^:^.]+)\\b`);function en(e,t){return({name:r,value:n})=>{let i=r.match(Dt()),o=r.match(/:([a-zA-Z0-9\-:]+)/),s=r.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],a=t||e[r]||r;return{type:i?i[1]:null,value:o?o[1]:null,modifiers:s.map(u=>u.replace(".","")),expression:n,original:a}}}var Ne="DEFAULT",$=["ignore","ref","data","id","bind","init","for","model","modelable","transition","show","if",Ne,"teleport"];function tn(e,t){let r=$.indexOf(e.type)===-1?Ne:e.type,n=$.indexOf(t.type)===-1?Ne:t.type;return $.indexOf(r)-$.indexOf(n)}function J(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}function M(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>M(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)M(n,t),n=n.nextElementSibling}function D(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}function rn(){document.body||D("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's `
diff --git a/conf/keycloak_theme/keywind/login/webauthn-error.ftl b/conf/keycloak_theme/keywind/login/webauthn-error.ftl
deleted file mode 100644
index 852d1e3d5..000000000
--- a/conf/keycloak_theme/keywind/login/webauthn-error.ftl
+++ /dev/null
@@ -1,34 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-
-<@layout.registrationLayout displayMessage=true; section>
- <#if section="header">
- ${kcSanitize(msg("webauthn-error-title"))?no_esc}
- <#elseif section="form">
-
-
- <@buttonGroup.kw>
- <@button.kw
- @click="$refs.executionValueInput.value = '${execution}'; $refs.isSetRetryInput.value = 'retry'; $refs.errorCredentialForm.submit()"
- color="primary"
- name="try-again"
- tabindex="4"
- type="button"
- >
- ${kcSanitize(msg("doTryAgain"))?no_esc}
- @button.kw>
- <#if isAppInitiatedAction??>
-
- #if>
- @buttonGroup.kw>
-
- #if>
-@layout.registrationLayout>
diff --git a/conf/keycloak_theme/keywind/login/webauthn-register.ftl b/conf/keycloak_theme/keywind/login/webauthn-register.ftl
deleted file mode 100644
index 57f4dad87..000000000
--- a/conf/keycloak_theme/keywind/login/webauthn-register.ftl
+++ /dev/null
@@ -1,54 +0,0 @@
-<#import "template.ftl" as layout>
-<#import "components/atoms/button.ftl" as button>
-<#import "components/atoms/button-group.ftl" as buttonGroup>
-
-<@layout.registrationLayout script="dist/webAuthnRegister.js"; section>
- <#if section="title">
- title
- <#elseif section="header">
- ${kcSanitize(msg("webauthn-registration-title"))?no_esc}
- <#elseif section="form">
-
-
- <@buttonGroup.kw>
- <@button.kw @click="registerSecurityKey" color="primary" type="submit">
- ${msg("doRegister")}
- @button.kw>
- <#if !isSetRetry?has_content && isAppInitiatedAction?has_content>
-
- #if>
- @buttonGroup.kw>
-
- #if>
-@layout.registrationLayout>
-
-
diff --git a/conf/sample.env_app-backend b/conf/sample.env_app-backend
deleted file mode 100644
index e75a8c98c..000000000
--- a/conf/sample.env_app-backend
+++ /dev/null
@@ -1,23 +0,0 @@
-## postgres database to store Hasura metadata
-HASURA_GRAPHQL_METADATA_DATABASE_URL=postgres://postgres:postgrespassword@postgres:5432/jan-hasura-metadata
-## this env var can be used to add the above postgres database to Hasura as a data source. this can be removed/updated based on your needs
-PG_DATABASE_URL=postgres://postgres:postgrespassword@postgres:5432/jan-hasura-data
-## enable the console served by server
-HASURA_GRAPHQL_ENABLE_CONSOLE="true" # set to "false" to disable console
-## enable debugging mode. It is recommended to disable this in production
-HASURA_GRAPHQL_DEV_MODE="true"
-HASURA_GRAPHQL_ENABLED_LOG_TYPES=startup, http-log, webhook-log, websocket-log, query-log
-## uncomment next line to run console offline (i.e load console assets from server instead of CDN)
-# HASURA_GRAPHQL_CONSOLE_ASSETS_DIR: /srv/console-assets
-## uncomment next line to set an admin secret
-HASURA_GRAPHQL_ADMIN_SECRET=myadminsecretkey
-HASURA_GRAPHQL_UNAUTHORIZED_ROLE="public"
-HASURA_GRAPHQL_METADATA_DEFAULTS='{"backend_configs":{"dataconnector":{"athena":{"uri":"http://data-connector-agent:8081/api/v1/athena"},"mariadb":{"uri":"http://data-connector-agent:8081/api/v1/mariadb"},"mysql8":{"uri":"http://data-connector-agent:8081/api/v1/mysql"},"oracle":{"uri":"http://data-connector-agent:8081/api/v1/oracle"},"snowflake":{"uri":"http://data-connector-agent:8081/api/v1/snowflake"}}}}'
-HASURA_GRAPHQL_JWT_SECRET={"jwk_url": "http://keycloak:8088/realms/hasura/protocol/openid-connect/certs"}
-
-# Environment variable for auto migrate
-HASURA_GRAPHQL_MIGRATIONS_DIR=/migrations
-HASURA_GRAPHQL_METADATA_DIR=/metadata
-HASURA_GRAPHQL_ENABLE_CONSOLE='true'
-HASURA_ACTION_STABLE_DIFFUSION_URL=http://sd:8000
-HASURA_EVENTS_HOOK_URL="http://worker:8787"
\ No newline at end of file
diff --git a/conf/sample.env_app-backend-postgres b/conf/sample.env_app-backend-postgres
deleted file mode 100644
index 39aa93db5..000000000
--- a/conf/sample.env_app-backend-postgres
+++ /dev/null
@@ -1 +0,0 @@
-POSTGRES_PASSWORD=postgrespassword
\ No newline at end of file
diff --git a/conf/sample.env_web-client b/conf/sample.env_web-client
deleted file mode 100644
index e024bb762..000000000
--- a/conf/sample.env_web-client
+++ /dev/null
@@ -1,15 +0,0 @@
-NEXT_PUBLIC_ENV=development
-NEXT_PUBLIC_WEB_URL=http://localhost:3000
-NEXT_PUBLIC_DISCORD_INVITATION_URL=#
-NEXT_PUBLIC_DOWNLOAD_APP_IOS=#
-NEXT_PUBLIC_DOWNLOAD_APP_ANDROID=#
-NEXT_PUBLIC_GRAPHQL_ENGINE_URL=http://localhost:8080/v1/graphql
-NEXT_PUBLIC_GRAPHQL_ENGINE_WEB_SOCKET_URL=ws://localhost:8080/v1/graphql
-NEXT_PUBLIC_OPENAPI_ENDPOINT=http://localhost:8000/v1/chat/completions
-KEYCLOAK_CLIENT_ID=hasura
-KEYCLOAK_CLIENT_SECRET=oMtCPAV7diKpE564SBspgKj4HqlKM4Hy
-AUTH_ISSUER=http://localhost:8088/realms/$KEYCLOAK_CLIENT_ID
-NEXTAUTH_URL=http://localhost:3000
-NEXTAUTH_SECRET=my-secret
-END_SESSION_URL=http://localhost:8088/realms/$KEYCLOAK_CLIENT_ID/protocol/openid-connect/logout
-REFRESH_TOKEN_URL=http://localhost:8088/realms/$KEYCLOAK_CLIENT_ID/protocol/openid-connect/token
diff --git a/docker-compose.yml b/docker-compose.yml
deleted file mode 100644
index 2a0c2bad7..000000000
--- a/docker-compose.yml
+++ /dev/null
@@ -1,121 +0,0 @@
-# docker version
-version: "3"
-
-services:
- keycloak:
- image: quay.io/keycloak/keycloak:${KEYCLOAK_VERSION-22.0.0}
- command: ["start-dev", "--import-realm", "--http-port", "8088"]
- environment:
- KC_DB: postgres
- KC_DB_URL_HOST: postgres
- KC_DB_URL_DATABASE: jan-keycloak
- KC_DB_PASSWORD: postgrespassword
- KC_DB_USERNAME: postgres
- KC_DB_SCHEMA: public
- KC_HEALTH_ENABLED: "true"
- KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN-admin}
- KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD-admin}
- volumes:
- - ./conf/keycloak_conf:/opt/keycloak/data/import
- - ./conf/keycloak_theme/keywind:/opt/keycloak/themes/keywind
- ports:
- - "8088:8088"
- depends_on:
- postgres:
- condition: service_healthy
- networks:
- jan_community:
- ipv4_address: 172.20.0.9
-
- postgres:
- image: postgres:15
- command: postgres -c jit=off
- restart: always
- environment:
- POSTGRES_USER: postgres
- POSTGRES_PASSWORD: postgrespassword
- ports:
- - "5432:5432"
- healthcheck:
- test: "exit 0"
- volumes:
- - ./conf/db/docker_psql_init.sql:/docker-entrypoint-initdb.d/docker_postgres_init.sql
- networks:
- jan_community:
- ipv4_address: 172.20.0.11
-
- graphql-engine:
- image: hasura/graphql-engine:v2.31.0.cli-migrations-v3
- ports:
- - 8080:8080
- restart: always
- env_file:
- - conf/sample.env_app-backend
- volumes:
- - ./app-backend/hasura/migrations:/migrations
- - ./app-backend/hasura/metadata:/metadata
- depends_on:
- data-connector-agent:
- condition: service_healthy
- keycloak:
- condition: service_started
- healthcheck:
- test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
- interval: 10s
- timeout: 10s
- retries: 30
- networks:
- jan_community:
- ipv4_address: 172.20.0.12
-
- data-connector-agent:
- image: hasura/graphql-data-connector:v2.31.0
- restart: always
- ports:
- - 8081:8081
- environment:
- QUARKUS_LOG_LEVEL: ERROR # FATAL, ERROR, WARN, INFO, DEBUG, TRACE
- ## https://quarkus.io/guides/opentelemetry#configuration-reference
- QUARKUS_OPENTELEMETRY_ENABLED: "false"
- ## QUARKUS_OPENTELEMETRY_TRACER_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317
- healthcheck:
- test: ["CMD", "curl", "-f", "http://localhost:8081/api/v1/athena/health"]
- interval: 5s
- timeout: 10s
- retries: 5
- start_period: 5s
- networks:
- jan_community:
- ipv4_address: 172.20.0.14
-
- web:
- build:
- context: ./web-client
- dockerfile: ./dev.Dockerfile
- restart: always
- volumes:
- - ./web-client/:/app
- - /app/node_modules
- - /app/.next
- env_file:
- - conf/sample.env_web-client
- ports:
- - 3000:3000
- environment:
- NODE_ENV: development
- extra_hosts:
- - "localhost:172.20.0.9"
- depends_on:
- graphql-engine:
- condition: service_healthy
- networks:
- jan_community:
- ipv4_address: 172.20.0.15
-
-networks:
- jan_community:
- driver: bridge
- ipam:
- driver: default
- config:
- - subnet: 172.20.0.0/16
diff --git a/app/electron/core/plugin-manager/execution/Activation.js b/electron/core/plugin-manager/execution/Activation.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/Activation.js
rename to electron/core/plugin-manager/execution/Activation.js
diff --git a/app/electron/core/plugin-manager/execution/ExtensionPoint.js b/electron/core/plugin-manager/execution/ExtensionPoint.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/ExtensionPoint.js
rename to electron/core/plugin-manager/execution/ExtensionPoint.js
diff --git a/app/electron/core/plugin-manager/execution/ExtensionPoint.test.js b/electron/core/plugin-manager/execution/ExtensionPoint.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/ExtensionPoint.test.js
rename to electron/core/plugin-manager/execution/ExtensionPoint.test.js
diff --git a/app/electron/core/plugin-manager/execution/Plugin.js b/electron/core/plugin-manager/execution/Plugin.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/Plugin.js
rename to electron/core/plugin-manager/execution/Plugin.js
diff --git a/app/electron/core/plugin-manager/execution/Plugin.test.js b/electron/core/plugin-manager/execution/Plugin.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/Plugin.test.js
rename to electron/core/plugin-manager/execution/Plugin.test.js
diff --git a/app/electron/core/plugin-manager/execution/activation-manager.js b/electron/core/plugin-manager/execution/activation-manager.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/activation-manager.js
rename to electron/core/plugin-manager/execution/activation-manager.js
diff --git a/app/electron/core/plugin-manager/execution/activation-manager.test.js b/electron/core/plugin-manager/execution/activation-manager.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/activation-manager.test.js
rename to electron/core/plugin-manager/execution/activation-manager.test.js
diff --git a/app/electron/core/plugin-manager/execution/extension-manager.js b/electron/core/plugin-manager/execution/extension-manager.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/extension-manager.js
rename to electron/core/plugin-manager/execution/extension-manager.js
diff --git a/app/electron/core/plugin-manager/execution/extension-manager.test.js b/electron/core/plugin-manager/execution/extension-manager.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/extension-manager.test.js
rename to electron/core/plugin-manager/execution/extension-manager.test.js
diff --git a/app/electron/core/plugin-manager/execution/facade.js b/electron/core/plugin-manager/execution/facade.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/facade.js
rename to electron/core/plugin-manager/execution/facade.js
diff --git a/app/electron/core/plugin-manager/execution/import-manager.js b/electron/core/plugin-manager/execution/import-manager.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/import-manager.js
rename to electron/core/plugin-manager/execution/import-manager.js
diff --git a/app/electron/core/plugin-manager/execution/index.js b/electron/core/plugin-manager/execution/index.js
similarity index 90%
rename from app/electron/core/plugin-manager/execution/index.js
rename to electron/core/plugin-manager/execution/index.js
index 3e0ce3820..83fe0ce17 100644
--- a/app/electron/core/plugin-manager/execution/index.js
+++ b/electron/core/plugin-manager/execution/index.js
@@ -2,10 +2,10 @@ import { definePresetEps, setImporter } from "./import-manager.js";
export * as extensionPoints from "./extension-manager.js";
export * as activationPoints from "./activation-manager.js";
-export * as plugins from "./facade";
+export * as plugins from "./facade.js";
export { default as ExtensionPoint } from "./ExtensionPoint.js";
-if (typeof window === "undefined" || !window.pluggableElectronIpc)
+if (typeof window !== "undefined" && !window.pluggableElectronIpc)
console.warn(
"Facade is not registered in preload. Facade functions will throw an error if used."
);
diff --git a/app/electron/core/plugin-manager/execution/index.test.js b/electron/core/plugin-manager/execution/index.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/execution/index.test.js
rename to electron/core/plugin-manager/execution/index.test.js
diff --git a/app/electron/core/plugin-manager/facade/index.js b/electron/core/plugin-manager/facade/index.js
similarity index 100%
rename from app/electron/core/plugin-manager/facade/index.js
rename to electron/core/plugin-manager/facade/index.js
diff --git a/app/electron/core/plugin-manager/facade/index.test.js b/electron/core/plugin-manager/facade/index.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/facade/index.test.js
rename to electron/core/plugin-manager/facade/index.test.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/Plugin.js b/electron/core/plugin-manager/pluginMgr/Plugin.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/Plugin.js
rename to electron/core/plugin-manager/pluginMgr/Plugin.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/Plugin.test.js b/electron/core/plugin-manager/pluginMgr/Plugin.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/Plugin.test.js
rename to electron/core/plugin-manager/pluginMgr/Plugin.test.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/globals.js b/electron/core/plugin-manager/pluginMgr/globals.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/globals.js
rename to electron/core/plugin-manager/pluginMgr/globals.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/index.js b/electron/core/plugin-manager/pluginMgr/index.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/index.js
rename to electron/core/plugin-manager/pluginMgr/index.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/index.test.js b/electron/core/plugin-manager/pluginMgr/index.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/index.test.js
rename to electron/core/plugin-manager/pluginMgr/index.test.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/router.js b/electron/core/plugin-manager/pluginMgr/router.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/router.js
rename to electron/core/plugin-manager/pluginMgr/router.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/store.js b/electron/core/plugin-manager/pluginMgr/store.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/store.js
rename to electron/core/plugin-manager/pluginMgr/store.js
diff --git a/app/electron/core/plugin-manager/pluginMgr/store.test.js b/electron/core/plugin-manager/pluginMgr/store.test.js
similarity index 100%
rename from app/electron/core/plugin-manager/pluginMgr/store.test.js
rename to electron/core/plugin-manager/pluginMgr/store.test.js
diff --git a/electron/core/plugins/data-plugin/README.md b/electron/core/plugins/data-plugin/README.md
new file mode 100644
index 000000000..2197d9ad2
--- /dev/null
+++ b/electron/core/plugins/data-plugin/README.md
@@ -0,0 +1,8 @@
+## Database handler plugin for Jan App
+
+**Notice**: please only install dependencies and run build using npm and not yarn.
+
+- index.ts: Main entry point for the plugin.
+- module.ts: Defines the plugin module which would be executed by the main node process.
+- package.json: Defines the plugin metadata.
+- tsconfig.json: Defines the typescript configuration.
diff --git a/electron/core/plugins/data-plugin/index.ts b/electron/core/plugins/data-plugin/index.ts
new file mode 100644
index 000000000..c2f91d89a
--- /dev/null
+++ b/electron/core/plugins/data-plugin/index.ts
@@ -0,0 +1,152 @@
+// Provide an async method to manipulate the price provided by the extension point
+const MODULE_PATH = "data-plugin/dist/module.js";
+
+const storeModel = (model: any) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "storeModel", model)
+ .then((res: any) => resolve(res));
+ }
+ });
+
+const getFinishedDownloadModels = () =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "getFinishedDownloadModels")
+ .then((res: any) => resolve(res));
+ }
+ });
+
+const getModelById = (modelId: string) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "getModelById", modelId)
+ .then((res: any) => resolve(res));
+ }
+ });
+
+const updateFinishedDownloadAt = (fileName: string) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(
+ MODULE_PATH,
+ "updateFinishedDownloadAt",
+ fileName,
+ Date.now()
+ )
+ .then((res: any) => resolve(res));
+ }
+ });
+
+const getUnfinishedDownloadModels = () =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "getUnfinishedDownloadModels")
+ .then((res: any[]) => resolve(res));
+ } else {
+ resolve([]);
+ }
+ });
+
+const deleteDownloadModel = (modelId: string) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "deleteDownloadModel", modelId)
+ .then((res: any) => resolve(res));
+ }
+ });
+
+const getConversations = () =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "getConversations")
+ .then((res: any[]) => resolve(res));
+ } else {
+ resolve([]);
+ }
+ });
+const getConversationMessages = (id: any) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "getConversationMessages", id)
+ .then((res: any[]) => resolve(res));
+ } else {
+ resolve([]);
+ }
+ });
+
+const createConversation = (conversation: any) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "storeConversation", conversation)
+ .then((res: any) => {
+ resolve(res);
+ });
+ } else {
+ resolve("-");
+ }
+ });
+const createMessage = (message: any) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "storeMessage", message)
+ .then((res: any) => resolve(res));
+ } else {
+ resolve("-");
+ }
+ });
+
+const deleteConversation = (id: any) =>
+ new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "deleteConversation", id)
+ .then((res: any) => {
+ resolve(res);
+ });
+ } else {
+ resolve("-");
+ }
+ });
+
+const setupDb = () => {
+ window.electronAPI.invokePluginFunc(MODULE_PATH, "init");
+};
+
+// Register all the above functions and objects with the relevant extension points
+export function init({ register }: { register: any }) {
+ setupDb();
+ register("getConversations", "getConv", getConversations, 1);
+ register("createConversation", "insertConv", createConversation);
+ register("deleteConversation", "deleteConv", deleteConversation);
+ register("createMessage", "insertMessage", createMessage);
+ register("getConversationMessages", "getMessages", getConversationMessages);
+ register("storeModel", "storeModel", storeModel);
+ register(
+ "updateFinishedDownloadAt",
+ "updateFinishedDownloadAt",
+ updateFinishedDownloadAt
+ );
+ register(
+ "getUnfinishedDownloadModels",
+ "getUnfinishedDownloadModels",
+ getUnfinishedDownloadModels
+ );
+ register("deleteDownloadModel", "deleteDownloadModel", deleteDownloadModel);
+ register("getModelById", "getModelById", getModelById);
+ register(
+ "getFinishedDownloadModels",
+ "getFinishedDownloadModels",
+ getFinishedDownloadModels
+ );
+}
diff --git a/electron/core/plugins/data-plugin/module.ts b/electron/core/plugins/data-plugin/module.ts
new file mode 100644
index 000000000..384e538ae
--- /dev/null
+++ b/electron/core/plugins/data-plugin/module.ts
@@ -0,0 +1,371 @@
+const sqlite3 = require("sqlite3").verbose();
+const path = require("path");
+const { app } = require("electron");
+
+const MODEL_TABLE_CREATION = `
+CREATE TABLE IF NOT EXISTS models (
+ id TEXT PRIMARY KEY,
+ slug TEXT NOT NULL,
+ name TEXT NOT NULL,
+ description TEXT NOT NULL,
+ avatar_url TEXT,
+ long_description TEXT NOT NULL,
+ technical_description TEXT NOT NULL,
+ author TEXT NOT NULL,
+ version TEXT NOT NULL,
+ model_url TEXT NOT NULL,
+ nsfw INTEGER NOT NULL,
+ greeting TEXT NOT NULL,
+ type TEXT NOT NULL,
+ file_name TEXT NOT NULL,
+ download_url TEXT NOT NULL,
+ start_download_at INTEGER DEFAULT -1,
+ finish_download_at INTEGER DEFAULT -1,
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
+);`;
+
+const MODEL_TABLE_INSERTION = `
+INSERT INTO models (
+ id,
+ slug,
+ name,
+ description,
+ avatar_url,
+ long_description,
+ technical_description,
+ author,
+ version,
+ model_url,
+ nsfw,
+ greeting,
+ type,
+ file_name,
+ download_url,
+ start_download_at
+) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
+
+function init() {
+ const db = new sqlite3.Database(path.join(app.getPath("userData"), "jan.db"));
+ console.log(
+ `Database located at ${path.join(app.getPath("userData"), "jan.db")}`
+ );
+
+ db.serialize(() => {
+ db.run(MODEL_TABLE_CREATION);
+ db.run(
+ "CREATE TABLE IF NOT EXISTS conversations ( id INTEGER PRIMARY KEY, name TEXT, model_id TEXT, image TEXT, message TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);"
+ );
+ db.run(
+ "CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY, name TEXT, conversation_id INTEGER, user TEXT, message TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP);"
+ );
+ });
+
+ const stmt = db.prepare(
+ "INSERT INTO conversations (name, model_id, image, message) VALUES (?, ?, ?, ?)"
+ );
+ stmt.finalize();
+ db.close();
+}
+
+/**
+ * Store a model in the database when user start downloading it
+ *
+ * @param model Product
+ */
+function storeModel(model: any) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+ console.debug("Inserting", JSON.stringify(model));
+ db.serialize(() => {
+ const stmt = db.prepare(MODEL_TABLE_INSERTION);
+ stmt.run(
+ model.id,
+ model.slug,
+ model.name,
+ model.description,
+ model.avatarUrl,
+ model.longDescription,
+ model.technicalDescription,
+ model.author,
+ model.version,
+ model.modelUrl,
+ model.nsfw,
+ model.greeting,
+ model.type,
+ model.fileName,
+ model.downloadUrl,
+ Date.now(),
+ function (err: any) {
+ if (err) {
+ // Handle the insertion error here
+ console.error(err.message);
+ res(undefined);
+ return;
+ }
+ // @ts-ignoreF
+ const id = this.lastID;
+ res(id);
+ return;
+ }
+ );
+ stmt.finalize();
+ });
+
+ db.close();
+ });
+}
+
+/**
+ * Update the finished download time of a model
+ *
+ * @param model Product
+ */
+function updateFinishedDownloadAt(fileName: string, time: number) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+ console.debug(`Updating fileName ${fileName} to ${time}`);
+ const stmt = `UPDATE models SET finish_download_at = ? WHERE file_name = ?`;
+ db.run(stmt, [time, fileName], (err: any) => {
+ if (err) {
+ console.log(err);
+ } else {
+ console.log("Updated 1 row");
+ res("Updated");
+ }
+ });
+
+ db.close();
+ });
+}
+
+/**
+ * Get all unfinished models from the database
+ */
+function getUnfinishedDownloadModels() {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ const query = `SELECT * FROM models WHERE finish_download_at = -1 ORDER BY start_download_at DESC`;
+ db.all(query, (err: Error, row: any) => {
+ res(row);
+ });
+ db.close();
+ });
+}
+
+function getFinishedDownloadModels() {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ const query = `SELECT * FROM models WHERE finish_download_at != -1 ORDER BY finish_download_at DESC`;
+ db.all(query, (err: Error, row: any) => {
+ res(row);
+ });
+ db.close();
+ });
+}
+
+function deleteDownloadModel(modelId: string) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+ console.log(`Deleting ${modelId}`);
+ db.serialize(() => {
+ const stmt = db.prepare("DELETE FROM models WHERE id = ?");
+ stmt.run(modelId);
+ stmt.finalize();
+ });
+
+ db.close();
+ });
+}
+
+function getModelById(modelId: string) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ console.debug("Get model by id", modelId);
+ db.get(
+ `SELECT * FROM models WHERE id = ?`,
+ [modelId],
+ (err: any, row: any) => {
+ console.debug("Get model by id result", row);
+
+ if (row) {
+ const product = {
+ id: row.id,
+ slug: row.slug,
+ name: row.name,
+ description: row.description,
+ avatarUrl: row.avatar_url,
+ longDescription: row.long_description,
+ technicalDescription: row.technical_description,
+ author: row.author,
+ version: row.version,
+ modelUrl: row.model_url,
+ nsfw: row.nsfw,
+ greeting: row.greeting,
+ type: row.type,
+ inputs: row.inputs,
+ outputs: row.outputs,
+ createdAt: new Date(row.created_at),
+ updatedAt: new Date(row.updated_at),
+ fileName: row.file_name,
+ downloadUrl: row.download_url,
+ };
+ res(product);
+ }
+ }
+ );
+
+ db.close();
+ });
+}
+
+function getConversations() {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ db.all(
+ "SELECT * FROM conversations ORDER BY created_at DESC",
+ (err: any, row: any) => {
+ res(row);
+ }
+ );
+ db.close();
+ });
+}
+function storeConversation(conversation: any) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ db.serialize(() => {
+ const stmt = db.prepare(
+ "INSERT INTO conversations (name, model_id, image, message) VALUES (?, ?, ?, ?)"
+ );
+ stmt.run(
+ conversation.name,
+ conversation.model_id,
+ conversation.image,
+ conversation.message,
+ function (err: any) {
+ if (err) {
+ // Handle the insertion error here
+ console.error(err.message);
+ res(undefined);
+ return;
+ }
+ // @ts-ignoreF
+ const id = this.lastID;
+ res(id);
+ return;
+ }
+ );
+ stmt.finalize();
+ });
+
+ db.close();
+ });
+}
+
+function storeMessage(message: any) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ db.serialize(() => {
+ const stmt = db.prepare(
+ "INSERT INTO messages (name, conversation_id, user, message) VALUES (?, ?, ?, ?)"
+ );
+ stmt.run(
+ message.name,
+ message.conversation_id,
+ message.user,
+ message.message,
+ (err: any) => {
+ if (err) {
+ // Handle the insertion error here
+ console.error(err.message);
+ res(undefined);
+ return;
+ }
+ //@ts-ignore
+ const id = this.lastID;
+ res(id);
+ return;
+ }
+ );
+ stmt.finalize();
+ });
+
+ db.close();
+ });
+}
+
+function deleteConversation(id: any) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ db.serialize(() => {
+ const deleteConv = db.prepare("DELETE FROM conversations WHERE id = ?");
+ deleteConv.run(id);
+ deleteConv.finalize();
+ const deleteMessages = db.prepare(
+ "DELETE FROM messages WHERE conversation_id = ?"
+ );
+ deleteMessages.run(id);
+ deleteMessages.finalize();
+ res([]);
+ });
+
+ db.close();
+ });
+}
+
+function getConversationMessages(conversation_id: any) {
+ return new Promise((res) => {
+ const db = new sqlite3.Database(
+ path.join(app.getPath("userData"), "jan.db")
+ );
+
+ const query = `SELECT * FROM messages WHERE conversation_id = ${conversation_id} ORDER BY created_at DESC`;
+ db.all(query, (err: Error, row: any) => {
+ res(row);
+ });
+ db.close();
+ });
+}
+
+module.exports = {
+ init,
+ getConversations,
+ deleteConversation,
+ storeConversation,
+ storeMessage,
+ getConversationMessages,
+ storeModel,
+ updateFinishedDownloadAt,
+ getUnfinishedDownloadModels,
+ getFinishedDownloadModels,
+ deleteDownloadModel,
+ getModelById,
+};
diff --git a/electron/core/plugins/data-plugin/package.json b/electron/core/plugins/data-plugin/package.json
new file mode 100644
index 000000000..83f148f7e
--- /dev/null
+++ b/electron/core/plugins/data-plugin/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "data-plugin",
+ "version": "2.1.0",
+ "description": "",
+ "main": "dist/index.js",
+ "author": "Jan",
+ "license": "MIT",
+ "activationPoints": [
+ "init"
+ ],
+ "scripts": {
+ "build": "tsc -b . && webpack --config webpack.config.js",
+ "build:package": "rimraf ./data-plugin*.tgz && npm run build && npm pack",
+ "build:publish": "npm run build:package && cpx *.tgz ../../pre-install"
+ },
+ "exports": {
+ ".": "./dist/index.js",
+ "./main": "./dist/module.js"
+ },
+ "devDependencies": {
+ "cpx": "^1.5.0",
+ "rimraf": "^3.0.2",
+ "ts-loader": "^9.4.4",
+ "ts-node": "^10.9.1",
+ "typescript": "^5.2.2",
+ "webpack": "^5.88.2",
+ "webpack-cli": "^5.1.4"
+ },
+ "bundledDependencies": [
+ "sql.js",
+ "sqlite3"
+ ],
+ "files": [
+ "dist/**",
+ "package.json",
+ "node_modules"
+ ],
+ "dependencies": {
+ "sqlite3": "^5.1.6"
+ }
+}
diff --git a/electron/core/plugins/data-plugin/tsconfig.json b/electron/core/plugins/data-plugin/tsconfig.json
new file mode 100644
index 000000000..72d6f3732
--- /dev/null
+++ b/electron/core/plugins/data-plugin/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig to read more about this file */
+ /* Language and Environment */
+ "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+ /* Modules */
+ "module": "ES6" /* Specify what module code is generated. */,
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */,
+ // "paths": {} /* Specify a set of entries that re-map imports to additional lookup locations. */,
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "resolveJsonModule": true, /* Enable importing .json files. */
+
+ "outDir": "./dist" /* Specify an output folder for all emitted files. */,
+ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
+ /* Type Checking */
+ "strict": false /* Enable all strict type-checking options. */,
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ }
+}
diff --git a/electron/core/plugins/data-plugin/types/index.d.ts b/electron/core/plugins/data-plugin/types/index.d.ts
new file mode 100644
index 000000000..a7ac3c8ac
--- /dev/null
+++ b/electron/core/plugins/data-plugin/types/index.d.ts
@@ -0,0 +1,7 @@
+export {};
+
+declare global {
+ interface Window {
+ electronAPI?: any | undefined;
+ }
+}
diff --git a/electron/core/plugins/data-plugin/webpack.config.js b/electron/core/plugins/data-plugin/webpack.config.js
new file mode 100644
index 000000000..18696aa34
--- /dev/null
+++ b/electron/core/plugins/data-plugin/webpack.config.js
@@ -0,0 +1,25 @@
+const path = require("path");
+
+module.exports = {
+ experiments: { outputModule: true },
+ entry: "./index.ts", // Adjust the entry point to match your project's main file
+ mode: "production",
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: "ts-loader",
+ exclude: /node_modules/,
+ },
+ ],
+ },
+ output: {
+ filename: "index.js", // Adjust the output file name as needed
+ path: path.resolve(__dirname, "dist"),
+ library: { type: "module" }, // Specify ESM output format
+ },
+ resolve: {
+ extensions: [".ts", ".js"],
+ },
+ // Add loaders and other configuration as needed for your project
+};
diff --git a/electron/core/plugins/inference-plugin/index.js b/electron/core/plugins/inference-plugin/index.js
new file mode 100644
index 000000000..76c1445fc
--- /dev/null
+++ b/electron/core/plugins/inference-plugin/index.js
@@ -0,0 +1,25 @@
+const MODULE_PATH = "inference-plugin/dist/module.js";
+
+const prompt = async (prompt) =>
+ new Promise(async (resolve) => {
+ if (window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "prompt", prompt)
+ .then((res) => resolve(res));
+ }
+ });
+
+const initModel = async (product) =>
+ new Promise(async (resolve) => {
+ if (window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "initModel", product)
+ .then((res) => resolve(res));
+ }
+ });
+
+// Register all the above functions and objects with the relevant extension points
+export function init({ register }) {
+ register("initModel", "initModel", initModel);
+ register("prompt", "prompt", prompt);
+}
diff --git a/electron/core/plugins/inference-plugin/module.js b/electron/core/plugins/inference-plugin/module.js
new file mode 100644
index 000000000..763c632cc
--- /dev/null
+++ b/electron/core/plugins/inference-plugin/module.js
@@ -0,0 +1,55 @@
+const path = require("path");
+const { app, dialog } = require("electron");
+const _importDynamic = new Function("modulePath", "return import(modulePath)");
+
+let llamaSession = null;
+
+async function initModel(product) {
+ // fileName fallback
+ if (!product.fileName) {
+ product.fileName = product.file_name;
+ }
+
+ if (!product.fileName) {
+ await dialog.showMessageBox({
+ message: "Selected model does not have file name..",
+ });
+
+ return;
+ }
+
+ console.info(`Initializing model: ${product.name}..`);
+ _importDynamic("../node_modules/node-llama-cpp/dist/index.js")
+ .then(({ LlamaContext, LlamaChatSession, LlamaModel }) => {
+ const modelPath = path.join(app.getPath("userData"), product.fileName);
+ const model = new LlamaModel({ modelPath });
+ const context = new LlamaContext({ model });
+ llamaSession = new LlamaChatSession({ context });
+ console.info(`Init model ${product.name} successfully!`);
+ })
+ .catch(async (e) => {
+ console.error(e);
+ await dialog.showMessageBox({
+ message: "Failed to import LLM module",
+ });
+ });
+}
+
+async function prompt(prompt) {
+ if (!llamaSession) {
+ await dialog.showMessageBox({
+ message: "Model not initialized",
+ });
+
+ return;
+ }
+ console.log("prompt: ", prompt);
+ const response = await llamaSession.prompt(prompt);
+ console.log("response: ", response);
+ return response;
+}
+
+module.exports = {
+ initModel,
+ prompt,
+};
diff --git a/electron/core/plugins/inference-plugin/package.json b/electron/core/plugins/inference-plugin/package.json
new file mode 100644
index 000000000..170a2f0eb
--- /dev/null
+++ b/electron/core/plugins/inference-plugin/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "inference-plugin",
+ "version": "0.0.1",
+ "description": "",
+ "main": "dist/index.js",
+ "author": "James",
+ "license": "MIT",
+ "activationPoints": [
+ "init"
+ ],
+ "scripts": {
+ "build": "webpack --config webpack.config.js",
+ "build:package": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && npm pack",
+ "build:publish": "yarn build:package && cpx *.tgz ../../pre-install"
+ },
+ "devDependencies": {
+ "cpx": "^1.5.0",
+ "rimraf": "^3.0.2",
+ "webpack": "^5.88.2",
+ "webpack-cli": "^5.1.4"
+ },
+ "bundledDependencies": [
+ "electron-is-dev",
+ "node-llama-cpp"
+ ],
+ "dependencies": {
+ "electron-is-dev": "^2.0.0",
+ "node-llama-cpp": "^2.4.1"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "files": [
+ "dist/*",
+ "package.json",
+ "README.md"
+ ]
+}
diff --git a/app/electron/core/model-management-plugin/webpack.config.js b/electron/core/plugins/inference-plugin/webpack.config.js
similarity index 64%
rename from app/electron/core/model-management-plugin/webpack.config.js
rename to electron/core/plugins/inference-plugin/webpack.config.js
index 7248a0990..2821852d4 100644
--- a/app/electron/core/model-management-plugin/webpack.config.js
+++ b/electron/core/plugins/inference-plugin/webpack.config.js
@@ -3,8 +3,18 @@ const path = require("path");
module.exports = {
experiments: { outputModule: true },
entry: "./index.js", // Adjust the entry point to match your project's main file
+ mode: "production",
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: "ts-loader",
+ exclude: /node_modules/,
+ },
+ ],
+ },
output: {
- filename: "bundle.js", // Adjust the output file name as needed
+ filename: "index.js", // Adjust the output file name as needed
path: path.resolve(__dirname, "dist"),
library: { type: "module" }, // Specify ESM output format
},
diff --git a/app/electron/core/model-management-plugin/index.js b/electron/core/plugins/model-management-plugin/index.js
similarity index 54%
rename from app/electron/core/model-management-plugin/index.js
rename to electron/core/plugins/model-management-plugin/index.js
index 1f934924f..0d2449931 100644
--- a/app/electron/core/model-management-plugin/index.js
+++ b/electron/core/plugins/model-management-plugin/index.js
@@ -1,39 +1,39 @@
+const MODULE_PATH = "model-management-plugin/dist/module.js";
+
const getDownloadedModels = async () =>
new Promise(async (resolve) => {
if (window.electronAPI) {
- const response = await window.electronAPI.getDownloadedModels();
- resolve(response);
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "getDownloadedModels")
+ .then((res) => resolve(res));
}
});
const getAvailableModels = async () =>
new Promise(async (resolve) => {
if (window.electronAPI) {
- const response = await window.electronAPI.getAvailableModels();
- resolve(response);
+ window.electronAPI
+ .invokePluginFunc(MODULE_PATH, "getAvailableModels")
+ .then((res) => resolve(res));
}
});
-const downloadModel = async (url) =>
+const downloadModel = async (product) =>
new Promise(async (resolve) => {
- if (window.electronAPI) {
- const response = await window.electronAPI.downloadModel(url);
- resolve(response);
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .downloadFile(product.downloadUrl, product.fileName)
+ .then((res) => resolve(res));
+ } else {
+ resolve("-");
}
});
const deleteModel = async (path) =>
new Promise(async (resolve) => {
if (window.electronAPI) {
- const response = await window.electronAPI.deleteModel(path);
- resolve(response);
- }
- });
-
-const initModel = async (product) =>
- new Promise(async (resolve) => {
- if (window.electronAPI) {
- const response = await window.electronAPI.initModel(product);
+ console.debug(`Delete model model management plugin: ${path}`);
+ const response = await window.electronAPI.deleteFile(path);
resolve(response);
}
});
@@ -44,5 +44,4 @@ export function init({ register }) {
register("getAvailableModels", "getAvailableModels", getAvailableModels);
register("downloadModel", "downloadModel", downloadModel);
register("deleteModel", "deleteModel", deleteModel);
- register("initModel", "initModel", initModel);
}
diff --git a/electron/core/plugins/model-management-plugin/module.js b/electron/core/plugins/model-management-plugin/module.js
new file mode 100644
index 000000000..d1472656b
--- /dev/null
+++ b/electron/core/plugins/model-management-plugin/module.js
@@ -0,0 +1,101 @@
+const path = require("path");
+const { readdirSync, lstatSync } = require("fs");
+const { app } = require("electron");
+
+const ALL_MODELS = [
+ {
+ id: "llama-2-7b-chat.Q4_K_M.gguf.bin",
+ slug: "llama-2-7b-chat.Q4_K_M.gguf.bin",
+ name: "Llama 2 7B Chat - GGUF",
+ description: "medium, balanced quality - recommended",
+ avatarUrl:
+ "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/6426d3f3a7723d62b53c259b/tvPikpAzKTKGN5wrpadOJ.jpeg?w=200&h=200&f=face",
+ longDescription:
+ "GGUF is a new format introduced by the llama.cpp team on August 21st 2023. It is a replacement for GGML, which is no longer supported by llama.cpp. GGUF offers numerous advantages over GGML, such as better tokenisation, and support for special tokens. It is also supports metadata, and is designed to be extensible.",
+ technicalDescription:
+ 'GGML_TYPE_Q4_K - "type-1" 4-bit quantization in super-blocks containing 8 blocks, each block having 32 weights. Scales and mins are quantized with 6 bits. This ends up using 4.5 bpw.',
+ author: "The Bloke",
+ version: "1.0.0",
+ modelUrl: "https://google.com",
+ nsfw: false,
+ greeting: "Hello there",
+ type: "LLM",
+ inputs: undefined,
+ outputs: undefined,
+ createdAt: 0,
+ updatedAt: undefined,
+ fileName: "llama-2-7b-chat.Q4_K_M.gguf.bin",
+ downloadUrl:
+ "https://huggingface.co/TheBloke/Llama-2-7b-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_M.gguf",
+ },
+ {
+ id: "llama-2-13b-chat.Q4_K_M.gguf",
+ slug: "llama-2-13b-chat.Q4_K_M.gguf",
+ name: "Llama 2 13B Chat - GGUF",
+ description: "medium, balanced quality - recommended",
+ avatarUrl:
+ "https://aeiljuispo.cloudimg.io/v7/https://cdn-uploads.huggingface.co/production/uploads/6426d3f3a7723d62b53c259b/tvPikpAzKTKGN5wrpadOJ.jpeg?w=200&h=200&f=face",
+ longDescription:
+ "GGUF is a new format introduced by the llama.cpp team on August 21st 2023. It is a replacement for GGML, which is no longer supported by llama.cpp. GGUF offers numerous advantages over GGML, such as better tokenisation, and support for special tokens. It is also supports metadata, and is designed to be extensible.",
+ technicalDescription:
+ 'GGML_TYPE_Q4_K - "type-1" 4-bit quantization in super-blocks containing 8 blocks, each block having 32 weights. Scales and mins are quantized with 6 bits. This ends up using 4.5 bpw.',
+ author: "The Bloke",
+ version: "1.0.0",
+ modelUrl: "https://google.com",
+ nsfw: false,
+ greeting: "Hello there",
+ type: "LLM",
+ inputs: undefined,
+ outputs: undefined,
+ createdAt: 0,
+ updatedAt: undefined,
+ fileName: "llama-2-13b-chat.Q4_K_M.gguf.bin",
+ downloadUrl:
+ "https://huggingface.co/TheBloke/Llama-2-13B-chat-GGUF/resolve/main/llama-2-13b-chat.Q4_K_M.gguf",
+ },
+];
+
+function getDownloadedModels() {
+ const userDataPath = app.getPath("userData");
+
+ const allBinariesName = [];
+ var files = readdirSync(userDataPath);
+ for (var i = 0; i < files.length; i++) {
+ var filename = path.join(userDataPath, files[i]);
+ var stat = lstatSync(filename);
+ if (stat.isDirectory()) {
+ // ignore
+ } else if (filename.endsWith(".bin")) {
+ var binaryName = path.basename(filename);
+ allBinariesName.push(binaryName);
+ }
+ }
+
+ const downloadedModels = ALL_MODELS.map((model) => {
+ if (
+ model.fileName &&
+ allBinariesName
+ .map((t) => t.toLowerCase())
+ .includes(model.fileName.toLowerCase())
+ ) {
+ return model;
+ }
+ return undefined;
+ }).filter((m) => m !== undefined);
+
+ return downloadedModels;
+}
+
+function getAvailableModels() {
+ const downloadedModelIds = getDownloadedModels().map((model) => model.id);
+ return ALL_MODELS.filter((model) => {
+ if (!downloadedModelIds.includes(model.id)) {
+ return model;
+ }
+ });
+}
+
+module.exports = {
+ getDownloadedModels,
+ getAvailableModels,
+};
diff --git a/app/electron/core/model-management-plugin/package.json b/electron/core/plugins/model-management-plugin/package.json
similarity index 57%
rename from app/electron/core/model-management-plugin/package.json
rename to electron/core/plugins/model-management-plugin/package.json
index cba07a937..dd7d61d3c 100644
--- a/app/electron/core/model-management-plugin/package.json
+++ b/electron/core/plugins/model-management-plugin/package.json
@@ -2,22 +2,23 @@
"name": "model-management-plugin",
"version": "0.0.1",
"description": "",
- "main": "dist/bundle.js",
+ "main": "dist/index.js",
"author": "James",
"license": "MIT",
"activationPoints": [
"init"
],
"scripts": {
- "prepare": "webpack --config webpack.config.js",
- "package": "rimraf ./*.tgz && npm pack"
+ "build": "webpack --config webpack.config.js",
+ "build:package": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && npm pack",
+ "build:publish": "yarn build:package && cpx *.tgz ../../pre-install"
},
"devDependencies": {
+ "cpx": "^1.5.0",
"rimraf": "^3.0.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4"
},
- "dependencies": {},
"files": [
"dist/*",
"package.json",
diff --git a/app/electron/core/data-plugin/webpack.config.js b/electron/core/plugins/model-management-plugin/webpack.config.js
similarity index 64%
rename from app/electron/core/data-plugin/webpack.config.js
rename to electron/core/plugins/model-management-plugin/webpack.config.js
index 7248a0990..2821852d4 100644
--- a/app/electron/core/data-plugin/webpack.config.js
+++ b/electron/core/plugins/model-management-plugin/webpack.config.js
@@ -3,8 +3,18 @@ const path = require("path");
module.exports = {
experiments: { outputModule: true },
entry: "./index.js", // Adjust the entry point to match your project's main file
+ mode: "production",
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: "ts-loader",
+ exclude: /node_modules/,
+ },
+ ],
+ },
output: {
- filename: "bundle.js", // Adjust the output file name as needed
+ filename: "index.js", // Adjust the output file name as needed
path: path.resolve(__dirname, "dist"),
library: { type: "module" }, // Specify ESM output format
},
diff --git a/electron/core/plugins/monitoring-plugin/index.js b/electron/core/plugins/monitoring-plugin/index.js
new file mode 100644
index 000000000..ac47a9adc
--- /dev/null
+++ b/electron/core/plugins/monitoring-plugin/index.js
@@ -0,0 +1,36 @@
+// Provide an async method to manipulate the price provided by the extension point
+const PLUGIN_NAME = "monitoring-plugin/dist/module.js";
+
+const getResourcesInfo = () => {
+ return new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(PLUGIN_NAME, "getResourcesInfo")
+ .then((res) => {
+ resolve(res);
+ });
+ } else {
+ resolve({});
+ }
+ });
+};
+
+const getCurrentLoad = () => {
+ return new Promise((resolve) => {
+ if (window && window.electronAPI) {
+ window.electronAPI
+ .invokePluginFunc(PLUGIN_NAME, "getCurrentLoad")
+ .then((res) => {
+ resolve(res);
+ });
+ } else {
+ resolve({});
+ }
+ });
+};
+
+// Register all the above functions and objects with the relevant extension points
+export function init({ register }) {
+ register("getResourcesInfo", "getResourcesInfo", getResourcesInfo);
+ register("getCurrentLoad", "getCurrentLoad", getCurrentLoad);
+}
diff --git a/electron/core/plugins/monitoring-plugin/module.js b/electron/core/plugins/monitoring-plugin/module.js
new file mode 100644
index 000000000..6fe5881c2
--- /dev/null
+++ b/electron/core/plugins/monitoring-plugin/module.js
@@ -0,0 +1,25 @@
+const si = require("systeminformation");
+
+const getResourcesInfo = async () =>
+ new Promise(async (resolve) => {
+ const cpu = await si.cpu();
+ const mem = await si.mem();
+ const gpu = await si.graphics();
+ const response = {
+ cpu,
+ mem,
+ gpu,
+ };
+ resolve(response);
+ });
+
+const getCurrentLoad = async () =>
+ new Promise(async (resolve) => {
+ const currentLoad = await si.currentLoad();
+ resolve(currentLoad);
+ });
+
+module.exports = {
+ getResourcesInfo,
+ getCurrentLoad,
+};
diff --git a/electron/core/plugins/monitoring-plugin/package.json b/electron/core/plugins/monitoring-plugin/package.json
new file mode 100644
index 000000000..34d110ab5
--- /dev/null
+++ b/electron/core/plugins/monitoring-plugin/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "monitoring-plugin",
+ "version": "0.0.1",
+ "description": "",
+ "main": "dist/bundle.js",
+ "author": "Jan",
+ "license": "MIT",
+ "activationPoints": [
+ "init"
+ ],
+ "scripts": {
+ "build": "webpack --config webpack.config.js",
+ "build:package": "rimraf ./*.tgz && npm run build && cpx \"module.js\" \"dist\" && npm pack",
+ "build:publish": "yarn build:package && cpx *.tgz ../../pre-install"
+ },
+ "devDependencies": {
+ "rimraf": "^3.0.2",
+ "webpack": "^5.88.2",
+ "webpack-cli": "^5.1.4"
+ },
+ "dependencies": {
+ "systeminformation": "^5.21.8"
+ },
+ "bundledDependencies": [
+ "systeminformation"
+ ],
+ "files": [
+ "dist/*",
+ "package.json",
+ "README.md"
+ ]
+}
diff --git a/app/electron/core/base-plugin/webpack.config.js b/electron/core/plugins/monitoring-plugin/webpack.config.js
similarity index 100%
rename from app/electron/core/base-plugin/webpack.config.js
rename to electron/core/plugins/monitoring-plugin/webpack.config.js
diff --git a/models/.gitkeep b/electron/core/pre-install/.gitkeep
similarity index 100%
rename from models/.gitkeep
rename to electron/core/pre-install/.gitkeep
diff --git a/electron/icon.png b/electron/icon.png
new file mode 100644
index 000000000..289f99ded
Binary files /dev/null and b/electron/icon.png differ
diff --git a/electron/main.ts b/electron/main.ts
new file mode 100644
index 000000000..5419668a5
--- /dev/null
+++ b/electron/main.ts
@@ -0,0 +1,204 @@
+import {
+ app,
+ BrowserWindow,
+ screen as electronScreen,
+ ipcMain,
+ dialog,
+ shell,
+} from "electron";
+import { readdirSync } from "fs";
+import { resolve, join, extname } from "path";
+import { unlink, createWriteStream } from "fs";
+import isDev = require("electron-is-dev");
+import { init } from "./core/plugin-manager/pluginMgr";
+const { autoUpdater } = require("electron-updater");
+// @ts-ignore
+import request = require("request");
+// @ts-ignore
+import progress = require("request-progress");
+
+let mainWindow: BrowserWindow | undefined = undefined;
+
+autoUpdater.autoDownload = false;
+autoUpdater.autoInstallOnAppQuit = true;
+
+const createMainWindow = () => {
+ mainWindow = new BrowserWindow({
+ width: electronScreen.getPrimaryDisplay().workArea.width,
+ height: electronScreen.getPrimaryDisplay().workArea.height,
+ show: false,
+ backgroundColor: "white",
+ webPreferences: {
+ nodeIntegration: true,
+ preload: join(__dirname, "preload.js"),
+ },
+ });
+
+ ipcMain.handle(
+ "invokePluginFunc",
+ async (event, modulePath, method, ...args) => {
+ const module = join(app.getPath("userData"), "plugins", modulePath);
+ return await import(/* webpackIgnore: true */ module)
+ .then((plugin) => {
+ if (typeof plugin[method] === "function") {
+ return plugin[method](...args);
+ } else {
+ console.log(plugin[method]);
+ console.error(`Function "${method}" does not exist in the module.`);
+ }
+ })
+ .then((res) => {
+ return res;
+ })
+ .catch((err) => console.log(err));
+ }
+ );
+
+ const startURL = isDev
+ ? "http://localhost:3000"
+ : `file://${join(__dirname, "../renderer/index.html")}`;
+
+ mainWindow.loadURL(startURL);
+
+ mainWindow.once("ready-to-show", () => mainWindow?.show());
+ mainWindow.on("closed", () => {
+ if (process.platform !== "darwin") app.quit();
+ });
+
+ if (isDev) mainWindow.webContents.openDevTools();
+};
+
+app.whenReady().then(() => {
+ createMainWindow();
+ setupPlugins();
+ autoUpdater.checkForUpdates();
+
+ ipcMain.handle("basePlugins", async (event) => {
+ const basePluginPath = join(
+ __dirname,
+ "../",
+ isDev ? "/core/pre-install" : "../app.asar.unpacked/core/pre-install"
+ );
+ return readdirSync(basePluginPath)
+ .filter((file) => extname(file) === ".tgz")
+ .map((file) => join(basePluginPath, file));
+ });
+
+ ipcMain.handle("pluginPath", async (event) => {
+ return join(app.getPath("userData"), "plugins");
+ });
+ ipcMain.handle("appVersion", async (event) => {
+ return app.getVersion();
+ });
+ ipcMain.handle("openExternalUrl", async (event, url) => {
+ shell.openExternal(url);
+ });
+
+ /**
+ * Used to delete a file from the user data folder
+ */
+ ipcMain.handle("deleteFile", async (_event, filePath) => {
+ const userDataPath = app.getPath("userData");
+ const fullPath = join(userDataPath, filePath);
+
+ let result = "NULL";
+ unlink(fullPath, function (err) {
+ if (err && err.code == "ENOENT") {
+ result = `File not exist: ${err}`;
+ } else if (err) {
+ result = `File delete error: ${err}`;
+ } else {
+ result = "File deleted successfully";
+ }
+ console.log(`Delete file ${filePath} from ${fullPath} result: ${result}`);
+ });
+
+ return result;
+ });
+
+ /**
+ * Used to download a file from a given url
+ */
+ ipcMain.handle("downloadFile", async (_event, url, fileName) => {
+ const userDataPath = app.getPath("userData");
+ const destination = resolve(userDataPath, fileName);
+
+ progress(request(url), {})
+ .on("progress", function (state: any) {
+ mainWindow?.webContents.send("FILE_DOWNLOAD_UPDATE", {
+ ...state,
+ fileName,
+ });
+ })
+ .on("error", function (err: Error) {
+ mainWindow?.webContents.send("FILE_DOWNLOAD_ERROR", {
+ fileName,
+ err,
+ });
+ })
+ .on("end", function () {
+ mainWindow?.webContents.send("FILE_DOWNLOAD_COMPLETE", {
+ fileName,
+ });
+ })
+ .pipe(createWriteStream(destination));
+ });
+
+ app.on("activate", () => {
+ if (!BrowserWindow.getAllWindows().length) {
+ createMainWindow();
+ }
+ });
+});
+
+/*New Update Available*/
+autoUpdater.on("update-available", async (info: any) => {
+ const action = await dialog.showMessageBox({
+ message: `Update available. Do you want to download the latest update?`,
+ buttons: ["Download", "Later"],
+ });
+ if (action.response === 0) await autoUpdater.downloadUpdate();
+});
+
+/*App Update Completion Message*/
+autoUpdater.on("update-downloaded", async (info: any) => {
+ mainWindow?.webContents.send("APP_UPDATE_COMPLETE", {});
+ const action = await dialog.showMessageBox({
+ message: `Update downloaded. Please restart the application to apply the updates.`,
+ buttons: ["Restart", "Later"],
+ });
+ if (action.response === 0) {
+ autoUpdater.quitAndInstall();
+ }
+});
+
+/*App Update Error */
+autoUpdater.on("error", (info: any) => {
+ dialog.showMessageBox({ message: info.message });
+ mainWindow?.webContents.send("APP_UPDATE_ERROR", {});
+});
+
+/*App Update Progress */
+autoUpdater.on("download-progress", (progress: any) => {
+ console.log("app update progress: ", progress.percent);
+ mainWindow?.webContents.send("APP_UPDATE_PROGRESS", {
+ percent: progress.percent,
+ });
+});
+
+app.on("window-all-closed", () => {
+ if (process.platform !== "darwin") {
+ app.quit();
+ }
+});
+
+function setupPlugins() {
+ init({
+ // Function to check from the main process that user wants to install a plugin
+ confirmInstall: async (plugins: string[]) => {
+ return true;
+ },
+ // Path to install plugin to
+ pluginsPath: join(app.getPath("userData"), "plugins"),
+ });
+}
diff --git a/electron/package.json b/electron/package.json
new file mode 100644
index 000000000..abb8ac016
--- /dev/null
+++ b/electron/package.json
@@ -0,0 +1,55 @@
+{
+ "name": "jan-electron",
+ "version": "0.1.1",
+ "main": "./build/main.js",
+ "author": "Jan",
+ "license": "MIT",
+ "homepage": "./",
+ "build": {
+ "appId": "jan.ai.app",
+ "productName": "Jan",
+ "files": [
+ "renderer/**/*",
+ "build/*.{js,map}",
+ "build/core/plugin-manager/**/*",
+ "core/pre-install"
+ ],
+ "asarUnpack": [
+ "core/pre-install"
+ ],
+ "publish": [
+ {
+ "provider": "github",
+ "owner": "janhq",
+ "repo": "jan"
+ }
+ ],
+ "extends": null,
+ "mac": {
+ "type": "distribution"
+ }
+ },
+ "scripts": {
+ "dev": "tsc -p . && electron .",
+ "build": "tsc -p . && electron-builder -p never -mw",
+ "build:publish": "tsc -p . && electron-builder -p onTagOrDraft -mw",
+ "postinstall": "electron-builder install-app-deps"
+ },
+ "dependencies": {
+ "electron-is-dev": "^2.0.0",
+ "electron-updater": "^6.1.4",
+ "node-llama-cpp": "^2.4.1",
+ "pluggable-electron": "^0.6.0",
+ "request": "^2.88.2",
+ "request-progress": "^3.0.0"
+ },
+ "devDependencies": {
+ "concurrently": "^8.2.1",
+ "electron": "26.2.1",
+ "electron-builder": "^24.6.4",
+ "wait-on": "^7.0.1"
+ },
+ "installConfig": {
+ "hoistingLimits": "workspaces"
+ }
+}
diff --git a/electron/preload.ts b/electron/preload.ts
new file mode 100644
index 000000000..18a9e78a0
--- /dev/null
+++ b/electron/preload.ts
@@ -0,0 +1,43 @@
+/* eslint-disable react-hooks/rules-of-hooks */
+// Make Pluggable Electron's facade available to the renderer on window.plugins
+//@ts-ignore
+const useFacade = require("pluggable-electron/facade");
+useFacade();
+//@ts-ignore
+const { contextBridge, ipcRenderer } = require("electron");
+
+contextBridge.exposeInMainWorld("electronAPI", {
+ invokePluginFunc: (plugin: any, method: any, ...args: any[]) =>
+ ipcRenderer.invoke("invokePluginFunc", plugin, method, ...args),
+
+ basePlugins: () => ipcRenderer.invoke("basePlugins"),
+
+ pluginPath: () => ipcRenderer.invoke("pluginPath"),
+
+ appVersion: () => ipcRenderer.invoke("appVersion"),
+
+ openExternalUrl: (url: string) => ipcRenderer.invoke("openExternalUrl", url),
+
+ deleteFile: (filePath: string) => ipcRenderer.invoke("deleteFile", filePath),
+
+ downloadFile: (url: string, path: string) =>
+ ipcRenderer.invoke("downloadFile", url, path),
+
+ onFileDownloadUpdate: (callback: any) =>
+ ipcRenderer.on("FILE_DOWNLOAD_UPDATE", callback),
+
+ onFileDownloadError: (callback: any) =>
+ ipcRenderer.on("FILE_DOWNLOAD_ERROR", callback),
+
+ onFileDownloadSuccess: (callback: any) =>
+ ipcRenderer.on("FILE_DOWNLOAD_COMPLETE", callback),
+
+ onAppUpdateDownloadUpdate: (callback: any) =>
+ ipcRenderer.on("APP_UPDATE_PROGRESS", callback),
+
+ onAppUpdateDownloadError: (callback: any) =>
+ ipcRenderer.on("APP_UPDATE_ERROR", callback),
+
+ onAppUpdateDownloadSuccess: (callback: any) =>
+ ipcRenderer.on("APP_UPDATE_COMPLETE", callback),
+});
diff --git a/electron/tsconfig.json b/electron/tsconfig.json
new file mode 100644
index 000000000..675a6abec
--- /dev/null
+++ b/electron/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "sourceMap": true,
+ "strict": true,
+ "outDir": "./build",
+ "rootDir": "./",
+ "noEmitOnError": true,
+ "allowJs": true,
+ "typeRoots": ["node_modules/@types"]
+ },
+ "exclude": ["core", "build", "node_modules"]
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..827d81d8a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "jan-app",
+ "private": true,
+ "workspaces": {
+ "packages": [
+ "electron",
+ "web"
+ ],
+ "nohoist": [
+ "electron",
+ "electron/**",
+ "web",
+ "web/**"
+ ]
+ },
+ "scripts": {
+ "dev:electron": "yarn workspace jan-electron dev",
+ "dev:web": "yarn workspace jan-web dev",
+ "dev": "concurrently --kill-others-on-fail \"yarn dev:web\" \"wait-on http://localhost:3000 && yarn dev:electron\"",
+ "build:web": "yarn workspace jan-web build && cpx \"web/out/**\" \"electron/renderer/\"",
+ "build:electron": "yarn workspace jan-electron build",
+ "build:plugins": "rm -f ./electron/core/pre-install/*.tgz && concurrently \"cd ./electron/core/plugins/data-plugin && npm install && npm run build:publish\" \"cd ./electron/core/plugins/inference-plugin && npm install && npm run build:publish\" \"cd ./electron/core/plugins/model-management-plugin && npm install && npm run build:publish\" \"cd ./electron/core/plugins/monitoring-plugin && npm install && npm run build:publish\"",
+ "build": "yarn build:web && yarn build:electron",
+ "build:publish": "yarn build:web && yarn workspace jan-electron build:publish"
+ },
+ "devDependencies": {
+ "concurrently": "^8.2.1",
+ "cpx": "^1.5.0",
+ "wait-on": "^7.0.1"
+ },
+ "version": "0.0.0"
+}
diff --git a/run.sh b/run.sh
deleted file mode 100755
index 2856f8770..000000000
--- a/run.sh
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/bin/bash
-### Clean sub-processes on exit
-trap "trap - SIGTERM && kill -- -$$" SIGINT
-
-MAX_STEPS=13
-progress() {
- local BAR_SIZE="##########"
- local MAX_BAR_SIZE="${#BAR_SIZE}"
- local CLEAR_LINE="\\033[K"
- spin[0]="-"
- spin[1]="\\"
- spin[2]="|"
- spin[3]="/"
- perc=$((($3 + 1) * 100 / MAX_STEPS))
- percBar=$((perc * MAX_BAR_SIZE / 100))
-
- eval "$1" >/dev/null 2>error.log &
- pid=$!
-
- echo -ne "\\r- [$3/$MAX_STEPS] [ ] $2 ...$CLEAR_LINE\\n"
- while kill -0 $pid >/dev/null 2>&1; do
- for i in "${spin[@]}"; do
- echo -ne "\\r\\033[1A- [$3/$MAX_STEPS] [$i] $2 $CLEAR_LINE\\n"
- sleep 0.1
- done
- done
- if [ -s "error.log" ] && [[ "$(cat error.log)" != "WARNING"* ]]; then
- echo -ne "\\r\\033[1A- [$3/$MAX_STEPS] [x] $2\\n $(cat error.log)"
- exit 1
- fi
- echo -ne "\\r\\033[1A- [$3/$MAX_STEPS] [✔] $2 $CLEAR_LINE\\n"
-}
-step=1
-
-mkdir -p models/
-
-### macOS setup
-if [[ "$OSTYPE" == "darwin"* ]]; then
- MAX_STEPS=13
- if [[ ! -x "$(command -v brew)" ]]; then
- progress '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' "Installing Homebrew" 1
- else
- progress '' "Homebrew - Installed" $((step++))
- fi
-
- xcode-select -p &>/dev/null
- if [ $? -ne 0 ]; then
- progress 'xcode-select --install' "Installing Xcode Command Line Tools" $((step++))
- else
- progress '' "Xcode Command Line Tools - Installed" $((step++))
- fi
-
- if [[ ! -x "$(command -v git)" ]]; then
- progress 'brew install git' "Installing Git" $((step++))
- else
- progress '' "Git - Installed" $((step++))
- fi
-
- if [[ ! -x "$(command -v wget)" ]]; then
- progress 'brew install wget' "Installing Wget" $((step++))
- else
- progress '' "Wget - Installed" $((step++))
- fi
-
- if [[ ! -x "$(command -v docker)" ]]; then
- progress 'brew install --cask docker' "Installing Docker" $((step++))
- else
- progress '' "Docker - Installed" $((step++))
- fi
-
- docker compose version &>/dev/null
- if [ $? -ne 0 ] && [ ! -x "$(command -v docker-compose)" ]; then
- progress 'brew install docker-compose' "Installing Docker Compose" $((step++))
- else
- progress '' "docker-compose - Installed" $((step++))
- fi
-fi
-###
-
-### Debian setup
-if [[ "$OSTYPE" == "linux"* ]]; then
- MAX_STEPS=12
- progress "sudo apt update 2>/dev/null" "Apt Updating" $((step++))
-
- if [[ ! -x "$(command -v git)" ]]; then
- progress 'sudo apt install git' "Installing Git" $((step++))
- else
- progress '' "Git - Installed" $((step++))
- fi
-
- if [[ ! -x "$(command -v wget)" ]]; then
- progress 'sudo apt install wget' "Installing Wget" $((step++))
- else
- progress '' "Wget - Installed" $((step++))
- fi
-
- if [[ ! -x "$(command -v docker)" ]]; then
- progress '/bin/bash -c "$(curl -fsSL https://get.docker.com/) 2>/dev/null"' "Installing Docker" $((step++))
- else
- progress '' "Docker - Installed" $((step++))
- fi
-
- docker compose version &>/dev/null
- if [ $? -ne 0 ] && [ ! -x "$(command -v docker-compose)" ]; then
- progress 'sudo apt install docker-compose' "Installing Docker Compose" $((step++))
- else
- progress '' "docker-compose - Installed" $((step++))
- fi
-fi
-###
-
-### Pull Jan
-if [ -d "jan" ]; then
- cd jan
- progress 'git pull 2>/dev/null' "Git pull" $((step++))
-else
- progress 'git clone --quiet https://github.com/janhq/jan' "Git clone" $((step++))
- cd jan
-fi
-
-progress 'git submodule update --init --recursive' "Pull submodule" $((step++))
-###
-
-### Prepare environment
-progress 'cp -f sample.env .env' "Prepare .env file" $((step++))
-###
-
-### Download Model
-if [ -f "/models/llama-2-7b.Q4_K_S.gguf" ]; then
- progress '' "Llama model - Installed" $((step++))
-else
- progress 'wget https://huggingface.co/TheBloke/Llama-2-7B-GGUF/resolve/main/llama-2-7b.Q4_K_S.gguf -P models' "Download Llama model" $((step++))
-fi
-###
-
-### Launch Docker & Docker compose up
-if [[ "$OSTYPE" == "darwin"* ]]; then
- progress $'
- if (! docker stats --no-stream 2>/dev/null ); then
- open /Applications/Docker.app
- while (! docker stats --no-stream 2>/dev/null ); do
- sleep 0.3
- done
- fi' "Waiting for docker to launch" $((step++))
-elif [[ "$OSTYPE" == "linux"* ]]; then
- progress 'sudo service docker start 2>/dev/null' "Starting Docker Service" $((step++))
-fi
-
-docker compose version &>/dev/null
-if [[ "$OSTYPE" == "darwin"* ]]; then
- if [ $? == 0 ]; then
- progress 'docker compose up -d --quiet-pull --remove-orphans 2>/dev/null' "Docker compose up" $((step++))
- elif [[ -x "$(command -v docker-compose)" ]]; then
- progress 'docker-compose up -d --quiet-pull --remove-orphans 2>/dev/null' "Docker compose up" $((step++))
- fi
-elif [[ "$OSTYPE" == "linux"* ]]; then
- if [[ $? == 0 ]]; then
- progress 'sudo docker compose up -d --quiet-pull --remove-orphans 2>/dev/null' "Docker compose up" $((step++))
- elif [[ -x "$(command -v docker-compose)" ]]; then
- progress 'sudo docker-compose up -d --quiet-pull --remove-orphans 2>/dev/null' "Docker compose up" $((step++))
- fi
-else
- echo >&2 "Can not find docker compose runner"
- exit 2
-fi
-
-###
-
-### Wait for service ready
-progress $'
- while (true); do
- if curl -sL -w "%{http_code}\\n" "http://localhost:3000" -o /dev/null | grep -q "200"; then
- break
- fi
-done
-' "Waiting for service ready" $((step++))
-###
-
-echo -ne "\\r You can now view Jan app in the browser: http://localhost:3000 \\n"
diff --git a/sample.env b/sample.env
deleted file mode 100644
index ab897ce1a..000000000
--- a/sample.env
+++ /dev/null
@@ -1,8 +0,0 @@
-KEYCLOAK_VERSION=22.0.0
-KEYCLOAK_ADMIN=admin
-KEYCLOAK_ADMIN_PASSWORD=admin
-
-# Inference
-## LLM
-LLM_MODEL_URL=https://huggingface.co/TheBloke/CodeLlama-13B-GGUF/resolve/main/codellama-13b.Q3_K_L.gguf
-LLM_MODEL_FILE=llama-2-7b-chat.ggmlv3.q4_1.bin
\ No newline at end of file
diff --git a/app/.eslintrc.json b/web/.eslintrc.json
similarity index 100%
rename from app/.eslintrc.json
rename to web/.eslintrc.json
diff --git a/app/.gitignore b/web/.gitignore
similarity index 100%
rename from app/.gitignore
rename to web/.gitignore
diff --git a/app/Dockerfile b/web/Dockerfile
similarity index 100%
rename from app/Dockerfile
rename to web/Dockerfile
diff --git a/app/app/_components/AdvancedPrompt/index.tsx b/web/app/_components/AdvancedPrompt/index.tsx
similarity index 100%
rename from app/app/_components/AdvancedPrompt/index.tsx
rename to web/app/_components/AdvancedPrompt/index.tsx
diff --git a/app/app/_components/AdvancedPromptGenerationParams/index.tsx b/web/app/_components/AdvancedPromptGenerationParams/index.tsx
similarity index 100%
rename from app/app/_components/AdvancedPromptGenerationParams/index.tsx
rename to web/app/_components/AdvancedPromptGenerationParams/index.tsx
diff --git a/app/app/_components/AdvancedPromptImageUpload/index.tsx b/web/app/_components/AdvancedPromptImageUpload/index.tsx
similarity index 100%
rename from app/app/_components/AdvancedPromptImageUpload/index.tsx
rename to web/app/_components/AdvancedPromptImageUpload/index.tsx
diff --git a/app/app/_components/AdvancedPromptResolution/index.tsx b/web/app/_components/AdvancedPromptResolution/index.tsx
similarity index 100%
rename from app/app/_components/AdvancedPromptResolution/index.tsx
rename to web/app/_components/AdvancedPromptResolution/index.tsx
diff --git a/app/app/_components/AdvancedPromptText/index.tsx b/web/app/_components/AdvancedPromptText/index.tsx
similarity index 100%
rename from app/app/_components/AdvancedPromptText/index.tsx
rename to web/app/_components/AdvancedPromptText/index.tsx
diff --git a/app/app/_components/AdvancedTextArea/index.tsx b/web/app/_components/AdvancedTextArea/index.tsx
similarity index 100%
rename from app/app/_components/AdvancedTextArea/index.tsx
rename to web/app/_components/AdvancedTextArea/index.tsx
diff --git a/app/app/_components/AiSearch/index.tsx b/web/app/_components/AiSearch/index.tsx
similarity index 100%
rename from app/app/_components/AiSearch/index.tsx
rename to web/app/_components/AiSearch/index.tsx
diff --git a/app/app/_components/AiTypeCard/index.tsx b/web/app/_components/AiTypeCard/index.tsx
similarity index 100%
rename from app/app/_components/AiTypeCard/index.tsx
rename to web/app/_components/AiTypeCard/index.tsx
diff --git a/app/app/_components/ApiStep/index.tsx b/web/app/_components/ApiStep/index.tsx
similarity index 100%
rename from app/app/_components/ApiStep/index.tsx
rename to web/app/_components/ApiStep/index.tsx
diff --git a/web/app/_components/AvailableModelCard/index.tsx b/web/app/_components/AvailableModelCard/index.tsx
new file mode 100644
index 000000000..64fc0f979
--- /dev/null
+++ b/web/app/_components/AvailableModelCard/index.tsx
@@ -0,0 +1,69 @@
+import { Product } from "@/_models/Product";
+import DownloadModelContent from "../DownloadModelContent";
+import ModelDownloadButton from "../ModelDownloadButton";
+import ModelDownloadingButton from "../ModelDownloadingButton";
+import ViewModelDetailButton from "../ViewModelDetailButton";
+import { useAtomValue } from "jotai";
+import { modelDownloadStateAtom } from "@/_helpers/JotaiWrapper";
+
+type Props = {
+ product: Product;
+ isRecommend: boolean;
+ required?: string;
+ onDownloadClick?: (product: Product) => void;
+};
+
+const AvailableModelCard: React.FC = ({
+ product,
+ isRecommend,
+ required,
+ onDownloadClick,
+}) => {
+ const downloadState = useAtomValue(modelDownloadStateAtom);
+
+ let isDownloading = false;
+ let total = 0;
+ let transferred = 0;
+
+ if (product.fileName && downloadState[product.fileName]) {
+ isDownloading =
+ downloadState[product.fileName].error == null &&
+ downloadState[product.fileName].percent < 1;
+
+ if (isDownloading) {
+ total = downloadState[product.fileName].size.total;
+ transferred = downloadState[product.fileName].size.transferred;
+ }
+ }
+
+ const handleViewDetails = () => {};
+
+ const downloadButton = isDownloading ? (
+
+
+
+ ) : (
+
+ onDownloadClick?.(product)} />
+
+ );
+
+ return (
+
+
+
+ {downloadButton}
+
+ {/*
*/}
+
+ );
+};
+
+export default AvailableModelCard;
diff --git a/app/app/_components/BasicPromptAccessories/index.tsx b/web/app/_components/BasicPromptAccessories/index.tsx
similarity index 100%
rename from app/app/_components/BasicPromptAccessories/index.tsx
rename to web/app/_components/BasicPromptAccessories/index.tsx
diff --git a/app/app/_components/BasicPromptButton/index.tsx b/web/app/_components/BasicPromptButton/index.tsx
similarity index 100%
rename from app/app/_components/BasicPromptButton/index.tsx
rename to web/app/_components/BasicPromptButton/index.tsx
diff --git a/app/app/_components/BasicPromptInput/index.tsx b/web/app/_components/BasicPromptInput/index.tsx
similarity index 100%
rename from app/app/_components/BasicPromptInput/index.tsx
rename to web/app/_components/BasicPromptInput/index.tsx
diff --git a/app/app/_components/ButtonSlider/index.tsx b/web/app/_components/ButtonSlider/index.tsx
similarity index 100%
rename from app/app/_components/ButtonSlider/index.tsx
rename to web/app/_components/ButtonSlider/index.tsx
diff --git a/app/app/_components/ChangeTheme/index.tsx b/web/app/_components/ChangeTheme/index.tsx
similarity index 100%
rename from app/app/_components/ChangeTheme/index.tsx
rename to web/app/_components/ChangeTheme/index.tsx
diff --git a/app/app/_components/ChatBody/index.tsx b/web/app/_components/ChatBody/index.tsx
similarity index 100%
rename from app/app/_components/ChatBody/index.tsx
rename to web/app/_components/ChatBody/index.tsx
diff --git a/app/app/_components/ChatBody/renderChatMessage.tsx b/web/app/_components/ChatBody/renderChatMessage.tsx
similarity index 100%
rename from app/app/_components/ChatBody/renderChatMessage.tsx
rename to web/app/_components/ChatBody/renderChatMessage.tsx
diff --git a/web/app/_components/ChatContainer/index.tsx b/web/app/_components/ChatContainer/index.tsx
new file mode 100644
index 000000000..46e740f90
--- /dev/null
+++ b/web/app/_components/ChatContainer/index.tsx
@@ -0,0 +1,29 @@
+"use client";
+
+import { useAtomValue } from "jotai";
+import { MainViewState, getMainViewStateAtom } from "@/_helpers/JotaiWrapper";
+import { ReactNode } from "react";
+import ModelManagement from "../ModelManagement";
+import Welcome from "../WelcomeContainer";
+import { Preferences } from "../Preferences";
+
+type Props = {
+ children: ReactNode;
+};
+
+export default function ChatContainer({ children }: Props) {
+ const viewState = useAtomValue(getMainViewStateAtom);
+
+ switch (viewState) {
+ case MainViewState.ExploreModel:
+ return ;
+ case MainViewState.Setting:
+ return ;
+ case MainViewState.ResourceMonitor:
+ case MainViewState.MyModel:
+ case MainViewState.Welcome:
+ return ;
+ default:
+ return {children}
;
+ }
+}
diff --git a/app/app/_components/ChatItem/index.tsx b/web/app/_components/ChatItem/index.tsx
similarity index 100%
rename from app/app/_components/ChatItem/index.tsx
rename to web/app/_components/ChatItem/index.tsx
diff --git a/app/app/_components/CompactHistoryItem/index.tsx b/web/app/_components/CompactHistoryItem/index.tsx
similarity index 100%
rename from app/app/_components/CompactHistoryItem/index.tsx
rename to web/app/_components/CompactHistoryItem/index.tsx
diff --git a/app/app/_components/CompactHistoryList/index.tsx b/web/app/_components/CompactHistoryList/index.tsx
similarity index 100%
rename from app/app/_components/CompactHistoryList/index.tsx
rename to web/app/_components/CompactHistoryList/index.tsx
diff --git a/app/app/_components/CompactLogo/index.tsx b/web/app/_components/CompactLogo/index.tsx
similarity index 100%
rename from app/app/_components/CompactLogo/index.tsx
rename to web/app/_components/CompactLogo/index.tsx
diff --git a/app/app/_components/CompactSideBar/index.tsx b/web/app/_components/CompactSideBar/index.tsx
similarity index 100%
rename from app/app/_components/CompactSideBar/index.tsx
rename to web/app/_components/CompactSideBar/index.tsx
diff --git a/app/app/_components/ConfirmDeleteConversationModal/index.tsx b/web/app/_components/ConfirmDeleteConversationModal/index.tsx
similarity index 100%
rename from app/app/_components/ConfirmDeleteConversationModal/index.tsx
rename to web/app/_components/ConfirmDeleteConversationModal/index.tsx
diff --git a/app/app/_components/ConfirmDeleteModelModal/index.tsx b/web/app/_components/ConfirmDeleteModelModal/index.tsx
similarity index 100%
rename from app/app/_components/ConfirmDeleteModelModal/index.tsx
rename to web/app/_components/ConfirmDeleteModelModal/index.tsx
diff --git a/app/app/_components/ConfirmSignOutModal/index.tsx b/web/app/_components/ConfirmSignOutModal/index.tsx
similarity index 100%
rename from app/app/_components/ConfirmSignOutModal/index.tsx
rename to web/app/_components/ConfirmSignOutModal/index.tsx
diff --git a/app/app/_components/ConversationalCard/index.tsx b/web/app/_components/ConversationalCard/index.tsx
similarity index 95%
rename from app/app/_components/ConversationalCard/index.tsx
rename to web/app/_components/ConversationalCard/index.tsx
index 7a93b2057..5be2142cf 100644
--- a/app/app/_components/ConversationalCard/index.tsx
+++ b/web/app/_components/ConversationalCard/index.tsx
@@ -14,9 +14,7 @@ const ConversationalCard: React.FC = ({ product }) => {
return (