diff --git a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html
index 4a9dc85865..242b4eab9c 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-login.html
@@ -1,240 +1,28 @@
-
-
-
-
-
-
-
![]()
-
-
-
-
-
+
+
+
+ Log in below.
+
+
+
diff --git a/src/Umbraco.Web.UI.Login/.env b/src/Umbraco.Web.UI.Login/.env
new file mode 100644
index 0000000000..7648c88cd2
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/.env
@@ -0,0 +1 @@
+# Copy this to .env.local and change what you want to test.
diff --git a/src/Umbraco.Web.UI.Login/.gitignore b/src/Umbraco.Web.UI.Login/.gitignore
new file mode 100644
index 0000000000..e45d6e3563
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/.gitignore
@@ -0,0 +1 @@
+*.local
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Login/.prettierrc.json b/src/Umbraco.Web.UI.Login/.prettierrc.json
new file mode 100644
index 0000000000..b828b574fb
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/.prettierrc.json
@@ -0,0 +1,8 @@
+{
+ "printWidth": 120,
+ "singleQuote": true,
+ "semi": true,
+ "bracketSpacing": true,
+ "bracketSameLine": true,
+ "useTabs": true
+}
diff --git a/src/Umbraco.Web.UI.Login/index.html b/src/Umbraco.Web.UI.Login/index.html
new file mode 100644
index 0000000000..8618e0c03f
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/index.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
Umbraco
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Login/package-lock.json b/src/Umbraco.Web.UI.Login/package-lock.json
new file mode 100644
index 0000000000..e0d86ab9a2
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/package-lock.json
@@ -0,0 +1,2660 @@
+{
+ "name": "login",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "login",
+ "dependencies": {
+ "@umbraco-ui/uui": "^1.4.0",
+ "@umbraco-ui/uui-css": "^1.4.0",
+ "lit": "^2.8.0",
+ "msw": "^1.3.2",
+ "rxjs": "^7.8.1"
+ },
+ "devDependencies": {
+ "typescript": "^5.2.2",
+ "vite": "^4.4.11"
+ },
+ "engines": {
+ "node": ">=18.16",
+ "npm": ">=9.5"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz",
+ "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz",
+ "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz",
+ "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz",
+ "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz",
+ "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz",
+ "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz",
+ "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz",
+ "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz",
+ "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz",
+ "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz",
+ "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz",
+ "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz",
+ "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz",
+ "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz",
+ "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz",
+ "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz",
+ "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz",
+ "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz",
+ "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz",
+ "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz",
+ "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz",
+ "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@lit-labs/ssr-dom-shim": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz",
+ "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g=="
+ },
+ "node_modules/@lit/reactive-element": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz",
+ "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==",
+ "dependencies": {
+ "@lit-labs/ssr-dom-shim": "^1.0.0"
+ }
+ },
+ "node_modules/@mswjs/cookies": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz",
+ "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==",
+ "dependencies": {
+ "@types/set-cookie-parser": "^2.4.0",
+ "set-cookie-parser": "^2.4.6"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@mswjs/interceptors": {
+ "version": "0.17.10",
+ "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.10.tgz",
+ "integrity": "sha512-N8x7eSLGcmUFNWZRxT1vsHvypzIRgQYdG0rJey/rZCy6zT/30qDt8Joj7FxzGNLSwXbeZqJOMqDurp7ra4hgbw==",
+ "dependencies": {
+ "@open-draft/until": "^1.0.3",
+ "@types/debug": "^4.1.7",
+ "@xmldom/xmldom": "^0.8.3",
+ "debug": "^4.3.3",
+ "headers-polyfill": "3.2.5",
+ "outvariant": "^1.2.1",
+ "strict-event-emitter": "^0.2.4",
+ "web-encoding": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@mswjs/interceptors/node_modules/strict-event-emitter": {
+ "version": "0.2.8",
+ "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz",
+ "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==",
+ "dependencies": {
+ "events": "^3.3.0"
+ }
+ },
+ "node_modules/@open-draft/until": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz",
+ "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q=="
+ },
+ "node_modules/@types/cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+ },
+ "node_modules/@types/debug": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.9.tgz",
+ "integrity": "sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow==",
+ "dependencies": {
+ "@types/ms": "*"
+ }
+ },
+ "node_modules/@types/js-levenshtein": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz",
+ "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g=="
+ },
+ "node_modules/@types/ms": {
+ "version": "0.7.32",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.32.tgz",
+ "integrity": "sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g=="
+ },
+ "node_modules/@types/node": {
+ "version": "20.4.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz",
+ "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw=="
+ },
+ "node_modules/@types/set-cookie-parser": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz",
+ "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz",
+ "integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ=="
+ },
+ "node_modules/@umbraco-ui/uui": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui/-/uui-1.4.0.tgz",
+ "integrity": "sha512-VG+C37WIS5Uv7ERDs/jQHT9mIncD9UrEsEQlgFnf2XZWc/TcBlV1Tvvt3xSYzZz9kIjwoymEG6lc5t6wJMqSfw==",
+ "dependencies": {
+ "@umbraco-ui/uui-action-bar": "1.4.0",
+ "@umbraco-ui/uui-avatar": "1.4.0",
+ "@umbraco-ui/uui-avatar-group": "1.4.0",
+ "@umbraco-ui/uui-badge": "1.4.0",
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-boolean-input": "1.4.0",
+ "@umbraco-ui/uui-box": "1.4.0",
+ "@umbraco-ui/uui-breadcrumbs": "1.4.0",
+ "@umbraco-ui/uui-button": "1.4.0",
+ "@umbraco-ui/uui-button-group": "1.4.0",
+ "@umbraco-ui/uui-button-inline-create": "1.4.0",
+ "@umbraco-ui/uui-card": "1.4.0",
+ "@umbraco-ui/uui-card-content-node": "1.4.0",
+ "@umbraco-ui/uui-card-media": "1.4.0",
+ "@umbraco-ui/uui-card-user": "1.4.0",
+ "@umbraco-ui/uui-caret": "1.4.0",
+ "@umbraco-ui/uui-checkbox": "1.4.0",
+ "@umbraco-ui/uui-color-area": "1.4.0",
+ "@umbraco-ui/uui-color-picker": "1.4.0",
+ "@umbraco-ui/uui-color-slider": "1.4.0",
+ "@umbraco-ui/uui-color-swatch": "1.4.0",
+ "@umbraco-ui/uui-color-swatches": "1.4.0",
+ "@umbraco-ui/uui-combobox": "1.4.0",
+ "@umbraco-ui/uui-combobox-list": "1.4.0",
+ "@umbraco-ui/uui-css": "1.4.0",
+ "@umbraco-ui/uui-dialog": "1.4.0",
+ "@umbraco-ui/uui-dialog-layout": "1.4.0",
+ "@umbraco-ui/uui-file-dropzone": "1.4.0",
+ "@umbraco-ui/uui-file-preview": "1.4.0",
+ "@umbraco-ui/uui-form": "1.4.0",
+ "@umbraco-ui/uui-form-layout-item": "1.4.0",
+ "@umbraco-ui/uui-form-validation-message": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0",
+ "@umbraco-ui/uui-icon-registry": "1.4.0",
+ "@umbraco-ui/uui-icon-registry-essential": "1.4.0",
+ "@umbraco-ui/uui-input": "1.4.0",
+ "@umbraco-ui/uui-input-file": "1.4.0",
+ "@umbraco-ui/uui-input-lock": "1.4.0",
+ "@umbraco-ui/uui-input-password": "1.4.0",
+ "@umbraco-ui/uui-keyboard-shortcut": "1.4.0",
+ "@umbraco-ui/uui-label": "1.4.0",
+ "@umbraco-ui/uui-loader": "1.4.0",
+ "@umbraco-ui/uui-loader-bar": "1.4.0",
+ "@umbraco-ui/uui-loader-circle": "1.4.0",
+ "@umbraco-ui/uui-menu-item": "1.4.0",
+ "@umbraco-ui/uui-modal": "1.4.0",
+ "@umbraco-ui/uui-pagination": "1.4.0",
+ "@umbraco-ui/uui-popover": "1.4.0",
+ "@umbraco-ui/uui-progress-bar": "1.4.0",
+ "@umbraco-ui/uui-radio": "1.4.0",
+ "@umbraco-ui/uui-range-slider": "1.4.0",
+ "@umbraco-ui/uui-ref": "1.4.0",
+ "@umbraco-ui/uui-ref-list": "1.4.0",
+ "@umbraco-ui/uui-ref-node": "1.4.0",
+ "@umbraco-ui/uui-ref-node-data-type": "1.4.0",
+ "@umbraco-ui/uui-ref-node-document-type": "1.4.0",
+ "@umbraco-ui/uui-ref-node-form": "1.4.0",
+ "@umbraco-ui/uui-ref-node-member": "1.4.0",
+ "@umbraco-ui/uui-ref-node-package": "1.4.0",
+ "@umbraco-ui/uui-ref-node-user": "1.4.0",
+ "@umbraco-ui/uui-scroll-container": "1.4.0",
+ "@umbraco-ui/uui-select": "1.4.0",
+ "@umbraco-ui/uui-slider": "1.4.0",
+ "@umbraco-ui/uui-symbol-expand": "1.4.0",
+ "@umbraco-ui/uui-symbol-file": "1.4.0",
+ "@umbraco-ui/uui-symbol-file-dropzone": "1.4.0",
+ "@umbraco-ui/uui-symbol-file-thumbnail": "1.4.0",
+ "@umbraco-ui/uui-symbol-folder": "1.4.0",
+ "@umbraco-ui/uui-symbol-lock": "1.4.0",
+ "@umbraco-ui/uui-symbol-more": "1.4.0",
+ "@umbraco-ui/uui-symbol-sort": "1.4.0",
+ "@umbraco-ui/uui-table": "1.4.0",
+ "@umbraco-ui/uui-tabs": "1.4.0",
+ "@umbraco-ui/uui-tag": "1.4.0",
+ "@umbraco-ui/uui-textarea": "1.4.0",
+ "@umbraco-ui/uui-toast-notification": "1.4.0",
+ "@umbraco-ui/uui-toast-notification-container": "1.4.0",
+ "@umbraco-ui/uui-toast-notification-layout": "1.4.0",
+ "@umbraco-ui/uui-toggle": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-action-bar": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-action-bar/-/uui-action-bar-1.4.0.tgz",
+ "integrity": "sha512-FMTSWXZOhWEziGL3OFvRGczAdRu2Ic82XLh4kCpCbRlKJHouqymOfo9FT3NbHEION37JUl9bv1nKiNA0m4s2bg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-button-group": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-avatar": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-avatar/-/uui-avatar-1.4.0.tgz",
+ "integrity": "sha512-sUvQKsaWXP+5xQO5p2YAqQyUITiyzIzK6cVRlGRUoEla3QlhCd7YHrRnrIJTNxwmfPygDtxGa9Zx8GNkW8N91w==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-avatar-group": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-avatar-group/-/uui-avatar-group-1.4.0.tgz",
+ "integrity": "sha512-xpWMumABRNqVH3sdLBH43gBk8RSNjknTvqfuvfMgdrVUqAYE3cIjeadUDf9OfmzMWVoQn7PXyLSX7l/JRUhZJQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-avatar": "1.4.0",
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-badge": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-badge/-/uui-badge-1.4.0.tgz",
+ "integrity": "sha512-6qUhcoGL43FWFS/Q6yozieaigQfKp2zqIrUGkdDpC3LqvUBshzuCFuDQEE+nobW/0oUkGV9MaMfa7hBI88eQTQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-base": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-base/-/uui-base-1.4.0.tgz",
+ "integrity": "sha512-RcNY2WfE2vTyAiDVyItBdo/o5owgMF16V+IFqa4xHeFlu1i08fp9/Qmyk+5Mb4LRJatt/V21zaOM0QlloyuNUg==",
+ "dependencies": {
+ "lit": "^2.3.1"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-boolean-input": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-boolean-input/-/uui-boolean-input-1.4.0.tgz",
+ "integrity": "sha512-yIhvUpT5KBE+nmROtYdrkyTg7k5OQd2f5YpSKK2RrAA1Ex7J7ZZpGIO4B7w6wNuZLLPA657YxRADwrPKU91nNw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-box": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-box/-/uui-box-1.4.0.tgz",
+ "integrity": "sha512-dQ8IeX86rAEmaz/ulJGDTGvmP0bMgm6LkRhGumignIRaVDLJdK5AIcPauVoq2n39IuczmoFjAEm6MFTAeQqZaQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-css": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-breadcrumbs": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-breadcrumbs/-/uui-breadcrumbs-1.4.0.tgz",
+ "integrity": "sha512-NfV8uVq093JceBC/Dog30iLi9z6ZwzwyS90At3qnCdIRn/ydxPghUA0xhS0Hf83GDQRgs9Ni7XbZv1P/SFdgrw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-button": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-button/-/uui-button-1.4.0.tgz",
+ "integrity": "sha512-8a6lZ/PLWg8iDuOv4YDhKvczWv844C3OfhPngLlmaK6UdkaiPlkxEoK41zZaVUV70B0ZhKk/odQYBp5nEUeeDA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-icon-registry-essential": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-button-group": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-button-group/-/uui-button-group-1.4.0.tgz",
+ "integrity": "sha512-Cwb1tFQbmo8XBpcTRwM5yolrselxBiDue0z+WyGWjKVuhNK/Cxlt1X2iT+MBlsgI1xW+I611+7d4n9V57wPXlQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-button-inline-create": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-button-inline-create/-/uui-button-inline-create-1.4.0.tgz",
+ "integrity": "sha512-pngszZKSk4uIaW0L06aBjBImKykxarNp7JTx6YJqi+rF+GXTS31/gRuckWN4pN0/BgUTJMd0Q11zVWfB0uwjvA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-card": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-card/-/uui-card-1.4.0.tgz",
+ "integrity": "sha512-eS5QdKzNqQQ+en3ZpPq88YGSWD1mSr4Nk9okpZ06fQmEZlYMMliR0A3WKFBQHhnleZafaEgHq3VwpVL1SQrluw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-card-content-node": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-card-content-node/-/uui-card-content-node-1.4.0.tgz",
+ "integrity": "sha512-8xbaSytLMsA7pXMKI4gttgiXjRgoQFh/pc3HzaQf3hKaWfeCPUxUaponXfZXmXjqMAi+eoyyxS1qeUt+Zlt0Rw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-card": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-card-media": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-card-media/-/uui-card-media-1.4.0.tgz",
+ "integrity": "sha512-rQT4m0KFYMelEszFExFMYYNIBHHcYlDd0alqiKitEUBlpu2UXCHK7mXyQlU+sFWLJ262zSONMmwSaXsqhMLVug==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-card": "1.4.0",
+ "@umbraco-ui/uui-symbol-file": "1.4.0",
+ "@umbraco-ui/uui-symbol-folder": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-card-user": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-card-user/-/uui-card-user-1.4.0.tgz",
+ "integrity": "sha512-t7C7F1sFrxAizNZJG7JDu+Wk0vizm7lN8UZCNggPiua6AkVVDpH8YN013Tk/reKxfTp9PkYh9aVUeAyyhWYa4g==",
+ "dependencies": {
+ "@umbraco-ui/uui-avatar": "1.4.0",
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-card": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-caret": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-caret/-/uui-caret-1.4.0.tgz",
+ "integrity": "sha512-RtWgCSvFelya+E0INy95XDiLNYDH3Tv7AdMvUTUKf/5PKYp/yR5MYo70P9EvUkCVMvIFVf/VVGd9mDwvLr2k+A==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-checkbox": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-checkbox/-/uui-checkbox-1.4.0.tgz",
+ "integrity": "sha512-VCcYycChEPmaOo5q2QF1xsxxYQ5XToGh/z+46GmFyc5TDFP2OyOWqVm6+4gVpljcvf4aS9IRqcoONa/Bv2LQqQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-boolean-input": "1.4.0",
+ "@umbraco-ui/uui-icon-registry-essential": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-color-area": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-color-area/-/uui-color-area-1.4.0.tgz",
+ "integrity": "sha512-csIswxLN9YDhmL6veZ9iR8SjQrDi8wscPPJB0i7w4TQDI8TwlvB0mAdb86FM0eoobXLPFeMDFkYGQijWpv69Gw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "colord": "^2.9.3"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-color-picker": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-color-picker/-/uui-color-picker-1.4.0.tgz",
+ "integrity": "sha512-zxOpmhEGEfQtLp/RYSPNBi8S2K+KjiuVyWhvmoqgO1gb/uNU5Om2xW1Q7pz/jiKe1qwWHO3whGl8LHM6el/C2w==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "colord": "^2.9.3"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-color-slider": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-color-slider/-/uui-color-slider-1.4.0.tgz",
+ "integrity": "sha512-XEgi6shSGCnB4LhQgalcWfsHXyC2oLGw0ZCANr9l/4LpjaoZ0Uq4H/CL8UFfwiLXbJWdzZwqQqJcP928QmUFYQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-color-swatch": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-color-swatch/-/uui-color-swatch-1.4.0.tgz",
+ "integrity": "sha512-/k1SgzfdA1sCueqDaGYXJyb+bZjMdffHgM4Qk5LMSjX3JDL+c6yKvoc/w2Bvky+9N1NUp+tEMbJKD7bzQalQlg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-icon-registry-essential": "1.4.0",
+ "colord": "^2.9.3"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-color-swatches": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-color-swatches/-/uui-color-swatches-1.4.0.tgz",
+ "integrity": "sha512-U6+0fu9OULPqRW0TuwVpj1PLectXM7ha2dc1Cw+rEzOtqBEbDmJTs4bh7EosMmxksmZQdXFhVkxu1yBHhXUJtQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-color-swatch": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-combobox": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-combobox/-/uui-combobox-1.4.0.tgz",
+ "integrity": "sha512-epBlmRtVlUKeToA+DbYJYEWzTvKQahm2RnUMzFk9BvISP1xE9X5q7MtZLPRoiTjA9wf4SYrxIgHlYBGUOmy9lQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-button": "1.4.0",
+ "@umbraco-ui/uui-combobox-list": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0",
+ "@umbraco-ui/uui-scroll-container": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-combobox-list": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-combobox-list/-/uui-combobox-list-1.4.0.tgz",
+ "integrity": "sha512-T6fOqHcOSB/NxfUmjZHlNWUU1ct9eVghXdQpA4tcPE83HSfHhWS5F1nbE9Cr/LO/al2Fe8iFfub9ed9OOsNqdA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-css": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-css/-/uui-css-1.4.0.tgz",
+ "integrity": "sha512-HBCFPuXJijeZbjnjdqmg3oqOGB3RmpQKT/s/Uy0TSJfaQGfz0e73o2eRghYHWF2rdqHw6brKFrZTZHBVvCE/xA==",
+ "dependencies": {
+ "lit": "^2.2.2"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-dialog": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-dialog/-/uui-dialog-1.4.0.tgz",
+ "integrity": "sha512-FCrz17nKh2zybsDeN0AIxBQJjSFhK1q8OdZGSzaegPKx6R/xmZBPx6KPZeQnmjdGzQJHwh4xILKHXGazZbIZXA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-css": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-dialog-layout": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-dialog-layout/-/uui-dialog-layout-1.4.0.tgz",
+ "integrity": "sha512-67/yVhysc+wMsyVEQXSP2E21YlzoQfir/CQjxCRlfKGe8FdCck/m3HSnzyb1rvPfbXrxGUMCUmcTqDBoazBfAw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-file-dropzone": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-file-dropzone/-/uui-file-dropzone-1.4.0.tgz",
+ "integrity": "sha512-pbNcTS7x7fvSyCrvR+yA7HzjWLtJXLHcLZvkJ4yNoAxS1d4/5ppyi/Fyz0QakBgLWzPuBv1mKj2o6RvBy29QWA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-symbol-file-dropzone": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-file-preview": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-file-preview/-/uui-file-preview-1.4.0.tgz",
+ "integrity": "sha512-UYi4Omww0/COjheTuAUdvZHqEAITT65Vsi5NSDHaUH3AM9BSVlj0FR3wOpwF7OwbOXjIeIonMEC8xMf1JtjusQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-symbol-file": "1.4.0",
+ "@umbraco-ui/uui-symbol-file-thumbnail": "1.4.0",
+ "@umbraco-ui/uui-symbol-folder": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-form": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-form/-/uui-form-1.4.0.tgz",
+ "integrity": "sha512-jjukKI+eoKmvw9Jc8n0ryle6gAA1ogQM3GLgId509qS9qiFGxMetMJ0KQjcRkrisRM/oQjz7huf9tF1es/prOQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-form-layout-item": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-form-layout-item/-/uui-form-layout-item-1.4.0.tgz",
+ "integrity": "sha512-aHBfwq7Y0YAWVHpiXZ1lnwSXyLbsGdk7lPkJ6hqVaBJ77VA/N2oDGMUjsRcCd1vKtD8AA3Nc2kT2e++NlUIPDg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-form-validation-message": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-form-validation-message": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-form-validation-message/-/uui-form-validation-message-1.4.0.tgz",
+ "integrity": "sha512-AZXcvusVb48H5YrPIj71iMMUOXn2pZtensi3fUj55sVY1RNFa+QuJW/vC/79qDBLw/vQJu3NcZGbi4q4NBKh9A==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-icon": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-icon/-/uui-icon-1.4.0.tgz",
+ "integrity": "sha512-aLzVYbubk+VSI4iKHJSKFxlHMe9CGq5JbaUfuy9a9U/D7VfUUrroM+tDMPFP4qEvSkjthyCzdPBxodJ+QQOZew==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-icon-registry": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-icon-registry/-/uui-icon-registry-1.4.0.tgz",
+ "integrity": "sha512-76XXyxq96XIp4qIT58UgY4vp4+agD2YvfpCd+Dhs/rdu5iQq56PmYoxJ7qr7JYTSf8xxZ//0/PiuamwWkPmSEw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-icon-registry-essential": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-icon-registry-essential/-/uui-icon-registry-essential-1.4.0.tgz",
+ "integrity": "sha512-o1woHz7YFjyOBIQHsdoCxE3vpXrJ/Sj0QNcGexdlFqUsvv/LhHAJ9a88cmTve1Y8nYDWW2pyyKZbyX1nDokByg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-icon-registry": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-input": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-input/-/uui-input-1.4.0.tgz",
+ "integrity": "sha512-mtlONZWmLV5OOYt2APhjl9cukTktrWNl1w4yF889F/wO2ZiGasBWwL9amtW4RIby/5nxns9yGgzXXG1/6GaqYw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-input-file": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-input-file/-/uui-input-file-1.4.0.tgz",
+ "integrity": "sha512-qdRce6NA6VDgFR71hUhuasX28N4qmCtWscWwoU+2E/rxfYWd2MIFOSsBqnIW6R4wagw+LnC7YXV6oy4vZiCKuQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-action-bar": "1.4.0",
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-button": "1.4.0",
+ "@umbraco-ui/uui-file-dropzone": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0",
+ "@umbraco-ui/uui-icon-registry-essential": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-input-lock": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-input-lock/-/uui-input-lock-1.4.0.tgz",
+ "integrity": "sha512-LK9jgCmSJFENRA+Hj7qnwhuhuYmMgWYPc44LMYdowqTKlkffr67mY2VqaK+92WbjmH8PKStJr0wf0L8tuEczWQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-button": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0",
+ "@umbraco-ui/uui-input": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-input-password": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-input-password/-/uui-input-password-1.4.0.tgz",
+ "integrity": "sha512-slxRycyh8okgl6vH89O/y9lWPkfrga6s3Myijz4RXnprWfVtntIkB5pZoM17yT9bjSfo15UKd4E4GdOS9YpcaQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-icon-registry-essential": "1.4.0",
+ "@umbraco-ui/uui-input": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-keyboard-shortcut": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-keyboard-shortcut/-/uui-keyboard-shortcut-1.4.0.tgz",
+ "integrity": "sha512-3hTFxrilMW7hGwfFtsNUmJdF0e4wk5pM8oGMuwwkKxsuxMdGzdpmht0PnB3G0EPQAsA60Xypiuvm0EgFnX91zg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-label": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-label/-/uui-label-1.4.0.tgz",
+ "integrity": "sha512-XTKH92Z0Apu15qI3MvJew1z3oAyOVBgByIipxVmWPb52Nlvj/Haa8QUlfksJWp4E4c2IhhYTPVXeft8CpS2q1w==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-loader": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-loader/-/uui-loader-1.4.0.tgz",
+ "integrity": "sha512-5KgUdzusuJeMwgIwtScuqgMnJ9NW+/G0/Osj3B20UBPwcwVm1z4s3cWlt3kKJmPA/W4fzbdTxRt2MRdSEp3+cw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-loader-bar": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-loader-bar/-/uui-loader-bar-1.4.0.tgz",
+ "integrity": "sha512-n+sxqJxp1aKy7lF8rbB9a72OzcdhTuHif5bR2XD2NwMmEZ7jl6xd+Em+sHo35ePqqmualpwetM2DlO50/uTDgg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-loader-circle": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-loader-circle/-/uui-loader-circle-1.4.0.tgz",
+ "integrity": "sha512-mFQB6psm9W4U/g9KEPPoUNFeEju2k/oJ+J5I1g0fz20HpfvDKIoebqErcCd0wngZfk4FZm1ditpN3t2eFGBR4A==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-menu-item": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-menu-item/-/uui-menu-item-1.4.0.tgz",
+ "integrity": "sha512-GqrjrUlzQzbctDzzg1X0fVRO4Yxll/H5oqnXZBuDZBpqu++AlXknqMuAjur0cFkeiV0Kn7N9w+uZl1NYWW9OJA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-loader-bar": "1.4.0",
+ "@umbraco-ui/uui-symbol-expand": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-modal": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-modal/-/uui-modal-1.4.0.tgz",
+ "integrity": "sha512-v+jiYIGCLTL4NY+Td5UIgoK52pxGVWxWEe+xxNJLYSUtiRsp+7dw9UwmNqLdflR3ngfyBVY+rfEXSfbcfjiQdA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-pagination": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-pagination/-/uui-pagination-1.4.0.tgz",
+ "integrity": "sha512-f38AuUTyZ5/JNWZFU02EzAaQ81R3sa38jClSjyDScQ9Vh+8Uwj16sRPnbnveFWU/c5URVMFpG5OGXA/RXI3WEg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-button": "1.4.0",
+ "@umbraco-ui/uui-button-group": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-popover": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-popover/-/uui-popover-1.4.0.tgz",
+ "integrity": "sha512-jbYHUGoN1S81VU4TbUh0HKipGcCnqiwINtQNDGf2W61Rgy++wBR3MfWqCaXd1K10GL8+wgkly6RsJKKUzqrDNw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-progress-bar": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-progress-bar/-/uui-progress-bar-1.4.0.tgz",
+ "integrity": "sha512-lJdoxiJMaDl7Qsaa6TkeuiudWV7Zer1LjWS9yO0aAZ4xWkkVxLf89qIlaTukdOat+Sr8ZtI2mjmRih5IjMdalg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-radio": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-radio/-/uui-radio-1.4.0.tgz",
+ "integrity": "sha512-pIJjmzWRIKPDxzwmB4CbBJNmMhlB97NOcgMoiIruiacVGEfZTWqXYXAkNtMragYGVQ0oz+ySYxEgl4iVvg2tdw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-range-slider": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-range-slider/-/uui-range-slider-1.4.0.tgz",
+ "integrity": "sha512-3rGrXEAOfztQHvD8aJlGuBfe0tXkpZgWtzq888D+8X68RMvPHs89X32FVqT8e34kK1/vfm8I7BwbDSXL6FTzbg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref/-/uui-ref-1.4.0.tgz",
+ "integrity": "sha512-zESd9N+72zON+kLCv95zzQtfmFY10zJU9DzzLR0GdZouujtyysU5qIwJG+dTy5ewm1jzGq5DHAyJtwO6IQSx7Q==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-list": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-list/-/uui-ref-list-1.4.0.tgz",
+ "integrity": "sha512-r8X0dSUsbvbyvK+2Yy7jsaCE4Q+PV7CDGQAO1eArYywCuJWjdVO18zt26Abvl1Z+v5qAWnbPiJHvF0h6mYTGMg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-node": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-node/-/uui-ref-node-1.4.0.tgz",
+ "integrity": "sha512-Jc8ews6mC9au4gUvzjRYfTeQWgFkrSICcsxd1oPz1qxVsyXWk66b3tWjAwkyjWwI13EOp4YoGK9QsPXbQKeTvg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0",
+ "@umbraco-ui/uui-ref": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-node-data-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-node-data-type/-/uui-ref-node-data-type-1.4.0.tgz",
+ "integrity": "sha512-tcuRnbYJxV8X3/ezP1gQ/DY2Vy9f+TDB/HFKtsNp+n891zShRbcEQ1As/fOoXGtM2JVAJ7VUYboyMhJ195hBVw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-ref-node": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-node-document-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-node-document-type/-/uui-ref-node-document-type-1.4.0.tgz",
+ "integrity": "sha512-pWESJsEm+Dect5kUws+sse0Xj8Z9+ZZkR1ZaeTHDL3kPMLxD6wMfMwWJtMeAIh7OvqJY0B/ldLonTof/ysebdA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-ref-node": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-node-form": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-node-form/-/uui-ref-node-form-1.4.0.tgz",
+ "integrity": "sha512-Xd17jQycvjq5TGfxkTZr+Kb/OU/lsUPkh4ft8/V4W/p0xv4sTio6txPw0bjDDcjJ/75zuHOLyTYicmcchcjXbA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-ref-node": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-node-member": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-node-member/-/uui-ref-node-member-1.4.0.tgz",
+ "integrity": "sha512-Lhpsh1CAwQRKOaR4tPkXBBZN3fjuEJMENlVHDB2UmmSJvFozl2byEWX4dEHwvPQpe0cbU8lE0By8iNDaEbl7Qw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-ref-node": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-node-package": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-node-package/-/uui-ref-node-package-1.4.0.tgz",
+ "integrity": "sha512-FQgAZ8NOjBVUWLyDg93pg6bqgONcM275qbqM3Htd+JMmmYcoYii/oTXlBqhGq7+9eDhcb8tGko2RN/tH9p8KSQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-ref-node": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-ref-node-user": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-ref-node-user/-/uui-ref-node-user-1.4.0.tgz",
+ "integrity": "sha512-dmp44LDXJbnupP8dnUpAMSPCU2+udhMSE9uQDx1hfmX08Q49Phw6R4Az9h1ESh5uSxSm6UEb/Y7JEblods7C3w==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-ref-node": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-scroll-container": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-scroll-container/-/uui-scroll-container-1.4.0.tgz",
+ "integrity": "sha512-/Rfqjtw+9LCCjvxl/MEmAjVfn4+aE8elfZ77EoItbF79R8WVmoJsIJUezjFp/Hvtp51PsgVgu/Da94dxTR4QBA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-select": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-select/-/uui-select-1.4.0.tgz",
+ "integrity": "sha512-bvdVIGot2vWiuoQmQL9dCriY8KnmpqLyn0q6FCvx7xGAl9nFBn1MfZFbs4INxriIGWjq17YFvUXklTWuhMLGTA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-slider": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-slider/-/uui-slider-1.4.0.tgz",
+ "integrity": "sha512-eDTIcXhYAiMSpPwI5e5gnMMpr0zOpx8te8pxF6K2YrGo8mCO2CI1zXZTzuv7e4ImL4HLmLoph8kbk+/wlrEtLw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-expand": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-expand/-/uui-symbol-expand-1.4.0.tgz",
+ "integrity": "sha512-vSWRYiUwTjERuWtbiAW7IB49s57bqjN2XrSmCrOtyS9i4t5jIjsZ11If97WD+gQI/tt+khQZ85oPWNcj6C3eVQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-file": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-file/-/uui-symbol-file-1.4.0.tgz",
+ "integrity": "sha512-wGmdw47jXjIcjpThf/TZ+6EZh+aQwqBA/1SMlgTtNBbUZDSy77NZ0pOWw8SaXzKqRrDqgFqIZukb7MILio3fwQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-file-dropzone": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-file-dropzone/-/uui-symbol-file-dropzone-1.4.0.tgz",
+ "integrity": "sha512-GftR6cK+9kbY43fV9a3+ICJX0rn8iT6SEe9vt85Uu4JMi2GCOT3TnKnIxgXRP3u9SyHhMNMiWmSgRfLpgJ2v/w==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-file-thumbnail": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-file-thumbnail/-/uui-symbol-file-thumbnail-1.4.0.tgz",
+ "integrity": "sha512-Xlu7NQ88AiQI9kfKOQKi1kH0zMkop7GqtGyuIXbnt7rM3EZfioTdltW1NvqgKzc2QpZPqMY1s449hravObHUUg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-folder": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-folder/-/uui-symbol-folder-1.4.0.tgz",
+ "integrity": "sha512-/cpV6Br3bOZkOh6YNr5PbIA/+NKKjyj1PkJwITSGm5/TnW2a4J5nzJTVn5ez7IjId176loRDZM2w05bemRavmA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-lock": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-lock/-/uui-symbol-lock-1.4.0.tgz",
+ "integrity": "sha512-BUPxOwhjjl4GVixbbGkKOPi9FI+C1fr1cy5NT2uLNY64z5r3jFzbnHMySKGzvpfig8wD+1hsuSPGP3lypzknOQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-more": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-more/-/uui-symbol-more-1.4.0.tgz",
+ "integrity": "sha512-fx125CCeBY+sspQpWITYt79AKYZ11NFaa72Zquz8cxH+hQA1z32jOUDL+m6oF3jTYwQkKQlCoff3VnOaJ91VyA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-symbol-sort": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-symbol-sort/-/uui-symbol-sort-1.4.0.tgz",
+ "integrity": "sha512-pVeT7qrKhRK8NUX3IDodSK0GNAKOKyWyzRhrxKrDT7wRuMManKmAK6WAVYpLaRqO+PRF8+NljfoCOEtJAHlGUg==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-table": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-table/-/uui-table-1.4.0.tgz",
+ "integrity": "sha512-wpEqTmUQrAWjloeHZQqzAt5HR+j5ihMJusHpqZmY4076LcvnmpZHPhtmwpIzosZNqRq2N1rbrPIyEotlzSg9Fw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-tabs": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-tabs/-/uui-tabs-1.4.0.tgz",
+ "integrity": "sha512-RWoLJHwMb9MbKqMyuyz3DaSc9ZGCa/NBtgBDpKpn/8oolbmNYBnr9e4sabHARtqfsEWFWKWP3kUw9iTQZNa0oA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-tag": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-tag/-/uui-tag-1.4.0.tgz",
+ "integrity": "sha512-9R+WJrJav780ZoA+dbZb7bHYazxrHxADnLdNOHoLvNyggLyxIT/SRsSxrP3x9zFRwbcRLZ8MRxQ3I32YiWacKw==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-textarea": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-textarea/-/uui-textarea-1.4.0.tgz",
+ "integrity": "sha512-nd6kWBmAvWaNLmXbEhfLRnWMfAp8rkll7XtHec9W32EQJwcHlYrS3wga6Xu32d3rKb3zUg+VXHh3EKKQH8M4uQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-toast-notification": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-toast-notification/-/uui-toast-notification-1.4.0.tgz",
+ "integrity": "sha512-ioiTTxqaOV/2ggnK9/IrnJPf1KRaKEIXd6qrXkMaYH1orCmv3BIdQMnl3TxFOM1YMlnbVZrfxBe2++iqV6TxHA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-button": "1.4.0",
+ "@umbraco-ui/uui-css": "1.4.0",
+ "@umbraco-ui/uui-icon": "1.4.0",
+ "@umbraco-ui/uui-icon-registry-essential": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-toast-notification-container": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-toast-notification-container/-/uui-toast-notification-container-1.4.0.tgz",
+ "integrity": "sha512-VIftKhOoQ0EdtM9pvDUM2IcvR8S9Fveh/QwMHgGLVlsgUogBNkCPGJKLfh9hzE5RS2v9FdPIkk72qP2A4fpspQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-toast-notification": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-toast-notification-layout": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-toast-notification-layout/-/uui-toast-notification-layout-1.4.0.tgz",
+ "integrity": "sha512-Secrk5+GlZYzOrg1MQ28+rLGW5krXYxYSAhSe5uDKOqTFLjuag7/qiraQDG3xBtf9ZfAAJ3qUy9n50adshoDbA==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-css": "1.4.0"
+ }
+ },
+ "node_modules/@umbraco-ui/uui-toggle": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@umbraco-ui/uui-toggle/-/uui-toggle-1.4.0.tgz",
+ "integrity": "sha512-APIOxs96fcn6HvD/SksN7rhEk6IAta7XU6s0T2Fa+RPIeOBS0NbbvFUX6hW3qjpiD5DdsjOpO2jn/R1fH3nqnQ==",
+ "dependencies": {
+ "@umbraco-ui/uui-base": "1.4.0",
+ "@umbraco-ui/uui-boolean-input": "1.4.0"
+ }
+ },
+ "node_modules/@xmldom/xmldom": {
+ "version": "0.8.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+ "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@zxing/text-encoding": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
+ "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
+ "optional": true
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-escapes/node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "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/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
+ "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz",
+ "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+ "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/colord": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="
+ },
+ "node_modules/cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "node_modules/esbuild": {
+ "version": "0.18.11",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz",
+ "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.18.11",
+ "@esbuild/android-arm64": "0.18.11",
+ "@esbuild/android-x64": "0.18.11",
+ "@esbuild/darwin-arm64": "0.18.11",
+ "@esbuild/darwin-x64": "0.18.11",
+ "@esbuild/freebsd-arm64": "0.18.11",
+ "@esbuild/freebsd-x64": "0.18.11",
+ "@esbuild/linux-arm": "0.18.11",
+ "@esbuild/linux-arm64": "0.18.11",
+ "@esbuild/linux-ia32": "0.18.11",
+ "@esbuild/linux-loong64": "0.18.11",
+ "@esbuild/linux-mips64el": "0.18.11",
+ "@esbuild/linux-ppc64": "0.18.11",
+ "@esbuild/linux-riscv64": "0.18.11",
+ "@esbuild/linux-s390x": "0.18.11",
+ "@esbuild/linux-x64": "0.18.11",
+ "@esbuild/netbsd-x64": "0.18.11",
+ "@esbuild/openbsd-x64": "0.18.11",
+ "@esbuild/sunos-x64": "0.18.11",
+ "@esbuild/win32-arm64": "0.18.11",
+ "@esbuild/win32-ia32": "0.18.11",
+ "@esbuild/win32-x64": "0.18.11"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "dependencies": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dependencies": {
+ "is-callable": "^1.1.3"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
+ "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graphql": {
+ "version": "16.8.1",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
+ "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
+ "engines": {
+ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "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==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+ "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
+ "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/headers-polyfill": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.2.5.tgz",
+ "integrity": "sha512-tUCGvt191vNSQgttSyJoibR+VO+I6+iCHIUdhzEMJKE+EAL8BwCN7fUOZlY4ofOelNHsK+gEjxB/B+9N3EWtdA=="
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "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/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/inquirer": {
+ "version": "8.2.5",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz",
+ "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==",
+ "dependencies": {
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.1.1",
+ "cli-cursor": "^3.1.0",
+ "cli-width": "^3.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^3.0.0",
+ "lodash": "^4.17.21",
+ "mute-stream": "0.0.8",
+ "ora": "^5.4.1",
+ "run-async": "^2.4.0",
+ "rxjs": "^7.5.5",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "through": "^2.3.6",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/is-arguments": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+ "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-generator-function": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
+ "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-node-process": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
+ "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw=="
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
+ "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
+ "dependencies": {
+ "which-typed-array": "^1.1.11"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/js-levenshtein": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
+ "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/lit": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz",
+ "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==",
+ "dependencies": {
+ "@lit/reactive-element": "^1.6.0",
+ "lit-element": "^3.3.0",
+ "lit-html": "^2.8.0"
+ }
+ },
+ "node_modules/lit-element": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz",
+ "integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==",
+ "dependencies": {
+ "@lit-labs/ssr-dom-shim": "^1.1.0",
+ "@lit/reactive-element": "^1.3.0",
+ "lit-html": "^2.8.0"
+ }
+ },
+ "node_modules/lit-html": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz",
+ "integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==",
+ "dependencies": {
+ "@types/trusted-types": "^2.0.2"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/msw": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/msw/-/msw-1.3.2.tgz",
+ "integrity": "sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@mswjs/cookies": "^0.2.2",
+ "@mswjs/interceptors": "^0.17.10",
+ "@open-draft/until": "^1.0.3",
+ "@types/cookie": "^0.4.1",
+ "@types/js-levenshtein": "^1.1.1",
+ "chalk": "^4.1.1",
+ "chokidar": "^3.4.2",
+ "cookie": "^0.4.2",
+ "graphql": "^16.8.1",
+ "headers-polyfill": "3.2.5",
+ "inquirer": "^8.2.0",
+ "is-node-process": "^1.2.0",
+ "js-levenshtein": "^1.1.6",
+ "node-fetch": "^2.6.7",
+ "outvariant": "^1.4.0",
+ "path-to-regexp": "^6.2.0",
+ "strict-event-emitter": "^0.4.3",
+ "type-fest": "^2.19.0",
+ "yargs": "^17.3.1"
+ },
+ "bin": {
+ "msw": "cli/index.js"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mswjs"
+ },
+ "peerDependencies": {
+ "typescript": ">= 4.4.x <= 5.2.x"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/mute-stream": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.12",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
+ "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+ "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+ "dependencies": {
+ "bl": "^4.1.0",
+ "chalk": "^4.1.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.5.0",
+ "is-interactive": "^1.0.0",
+ "is-unicode-supported": "^0.1.0",
+ "log-symbols": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/outvariant": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz",
+ "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw=="
+ },
+ "node_modules/path-to-regexp": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
+ "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
+ },
+ "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/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.27",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
+ "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "3.28.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz",
+ "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+ "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "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==",
+ "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/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/set-cookie-parser": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
+ "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ=="
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strict-event-emitter": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz",
+ "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg=="
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
+ },
+ "node_modules/tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dependencies": {
+ "os-tmpdir": "~1.0.2"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "node_modules/tslib": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
+ "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA=="
+ },
+ "node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
+ "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
+ "devOptional": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/util": {
+ "version": "0.12.5",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
+ "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "is-arguments": "^1.0.4",
+ "is-generator-function": "^1.0.7",
+ "is-typed-array": "^1.1.3",
+ "which-typed-array": "^1.1.2"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "node_modules/vite": {
+ "version": "4.4.11",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz",
+ "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==",
+ "dev": true,
+ "dependencies": {
+ "esbuild": "^0.18.10",
+ "postcss": "^8.4.27",
+ "rollup": "^3.27.1"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@types/node": ">= 14",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "node_modules/web-encoding": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz",
+ "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==",
+ "dependencies": {
+ "util": "^0.12.3"
+ },
+ "optionalDependencies": {
+ "@zxing/text-encoding": "0.9.0"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz",
+ "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.5",
+ "call-bind": "^1.0.2",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "engines": {
+ "node": ">=12"
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/package.json b/src/Umbraco.Web.UI.Login/package.json
new file mode 100644
index 0000000000..c5fdbf6a25
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "login",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "watch": "tsc && vite build --watch",
+ "preview": "vite preview"
+ },
+ "engines": {
+ "node": ">=18.16",
+ "npm": ">=9.5"
+ },
+ "dependencies": {
+ "@umbraco-ui/uui": "^1.4.0",
+ "@umbraco-ui/uui-css": "^1.4.0",
+ "lit": "^2.8.0",
+ "msw": "^1.3.2",
+ "rxjs": "^7.8.1"
+ },
+ "devDependencies": {
+ "typescript": "^5.2.2",
+ "vite": "^4.4.11"
+ },
+ "msw": {
+ "workerDirectory": "public"
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/public/favicon.svg b/src/Umbraco.Web.UI.Login/public/favicon.svg
new file mode 100644
index 0000000000..19acb4bc1e
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/public/favicon.svg
@@ -0,0 +1,17 @@
+
+
+
diff --git a/src/Umbraco.Web.UI.Login/public/login.svg b/src/Umbraco.Web.UI.Login/public/login.svg
new file mode 100644
index 0000000000..37499a996c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/public/login.svg
@@ -0,0 +1,996 @@
+
+
+
diff --git a/src/Umbraco.Web.UI.Login/public/mockServiceWorker.js b/src/Umbraco.Web.UI.Login/public/mockServiceWorker.js
new file mode 100644
index 0000000000..51d85eeebf
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/public/mockServiceWorker.js
@@ -0,0 +1,303 @@
+/* eslint-disable */
+/* tslint:disable */
+
+/**
+ * Mock Service Worker (1.3.2).
+ * @see https://github.com/mswjs/msw
+ * - Please do NOT modify this file.
+ * - Please do NOT serve this file on production.
+ */
+
+const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70'
+const activeClientIds = new Set()
+
+self.addEventListener('install', function () {
+ self.skipWaiting()
+})
+
+self.addEventListener('activate', function (event) {
+ event.waitUntil(self.clients.claim())
+})
+
+self.addEventListener('message', async function (event) {
+ const clientId = event.source.id
+
+ if (!clientId || !self.clients) {
+ return
+ }
+
+ const client = await self.clients.get(clientId)
+
+ if (!client) {
+ return
+ }
+
+ const allClients = await self.clients.matchAll({
+ type: 'window',
+ })
+
+ switch (event.data) {
+ case 'KEEPALIVE_REQUEST': {
+ sendToClient(client, {
+ type: 'KEEPALIVE_RESPONSE',
+ })
+ break
+ }
+
+ case 'INTEGRITY_CHECK_REQUEST': {
+ sendToClient(client, {
+ type: 'INTEGRITY_CHECK_RESPONSE',
+ payload: INTEGRITY_CHECKSUM,
+ })
+ break
+ }
+
+ case 'MOCK_ACTIVATE': {
+ activeClientIds.add(clientId)
+
+ sendToClient(client, {
+ type: 'MOCKING_ENABLED',
+ payload: true,
+ })
+ break
+ }
+
+ case 'MOCK_DEACTIVATE': {
+ activeClientIds.delete(clientId)
+ break
+ }
+
+ case 'CLIENT_CLOSED': {
+ activeClientIds.delete(clientId)
+
+ const remainingClients = allClients.filter((client) => {
+ return client.id !== clientId
+ })
+
+ // Unregister itself when there are no more clients
+ if (remainingClients.length === 0) {
+ self.registration.unregister()
+ }
+
+ break
+ }
+ }
+})
+
+self.addEventListener('fetch', function (event) {
+ const { request } = event
+ const accept = request.headers.get('accept') || ''
+
+ // Bypass server-sent events.
+ if (accept.includes('text/event-stream')) {
+ return
+ }
+
+ // Bypass navigation requests.
+ if (request.mode === 'navigate') {
+ return
+ }
+
+ // Opening the DevTools triggers the "only-if-cached" request
+ // that cannot be handled by the worker. Bypass such requests.
+ if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
+ return
+ }
+
+ // Bypass all requests when there are no active clients.
+ // Prevents the self-unregistered worked from handling requests
+ // after it's been deleted (still remains active until the next reload).
+ if (activeClientIds.size === 0) {
+ return
+ }
+
+ // Generate unique request ID.
+ const requestId = Math.random().toString(16).slice(2)
+
+ event.respondWith(
+ handleRequest(event, requestId).catch((error) => {
+ if (error.name === 'NetworkError') {
+ console.warn(
+ '[MSW] Successfully emulated a network error for the "%s %s" request.',
+ request.method,
+ request.url,
+ )
+ return
+ }
+
+ // At this point, any exception indicates an issue with the original request/response.
+ console.error(
+ `\
+[MSW] Caught an exception from the "%s %s" request (%s). This is probably not a problem with Mock Service Worker. There is likely an additional logging output above.`,
+ request.method,
+ request.url,
+ `${error.name}: ${error.message}`,
+ )
+ }),
+ )
+})
+
+async function handleRequest(event, requestId) {
+ const client = await resolveMainClient(event)
+ const response = await getResponse(event, client, requestId)
+
+ // Send back the response clone for the "response:*" life-cycle events.
+ // Ensure MSW is active and ready to handle the message, otherwise
+ // this message will pend indefinitely.
+ if (client && activeClientIds.has(client.id)) {
+ ;(async function () {
+ const clonedResponse = response.clone()
+ sendToClient(client, {
+ type: 'RESPONSE',
+ payload: {
+ requestId,
+ type: clonedResponse.type,
+ ok: clonedResponse.ok,
+ status: clonedResponse.status,
+ statusText: clonedResponse.statusText,
+ body:
+ clonedResponse.body === null ? null : await clonedResponse.text(),
+ headers: Object.fromEntries(clonedResponse.headers.entries()),
+ redirected: clonedResponse.redirected,
+ },
+ })
+ })()
+ }
+
+ return response
+}
+
+// Resolve the main client for the given event.
+// Client that issues a request doesn't necessarily equal the client
+// that registered the worker. It's with the latter the worker should
+// communicate with during the response resolving phase.
+async function resolveMainClient(event) {
+ const client = await self.clients.get(event.clientId)
+
+ if (client?.frameType === 'top-level') {
+ return client
+ }
+
+ const allClients = await self.clients.matchAll({
+ type: 'window',
+ })
+
+ return allClients
+ .filter((client) => {
+ // Get only those clients that are currently visible.
+ return client.visibilityState === 'visible'
+ })
+ .find((client) => {
+ // Find the client ID that's recorded in the
+ // set of clients that have registered the worker.
+ return activeClientIds.has(client.id)
+ })
+}
+
+async function getResponse(event, client, requestId) {
+ const { request } = event
+ const clonedRequest = request.clone()
+
+ function passthrough() {
+ // Clone the request because it might've been already used
+ // (i.e. its body has been read and sent to the client).
+ const headers = Object.fromEntries(clonedRequest.headers.entries())
+
+ // Remove MSW-specific request headers so the bypassed requests
+ // comply with the server's CORS preflight check.
+ // Operate with the headers as an object because request "Headers"
+ // are immutable.
+ delete headers['x-msw-bypass']
+
+ return fetch(clonedRequest, { headers })
+ }
+
+ // Bypass mocking when the client is not active.
+ if (!client) {
+ return passthrough()
+ }
+
+ // Bypass initial page load requests (i.e. static assets).
+ // The absence of the immediate/parent client in the map of the active clients
+ // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
+ // and is not ready to handle requests.
+ if (!activeClientIds.has(client.id)) {
+ return passthrough()
+ }
+
+ // Bypass requests with the explicit bypass header.
+ // Such requests can be issued by "ctx.fetch()".
+ if (request.headers.get('x-msw-bypass') === 'true') {
+ return passthrough()
+ }
+
+ // Notify the client that a request has been intercepted.
+ const clientMessage = await sendToClient(client, {
+ type: 'REQUEST',
+ payload: {
+ id: requestId,
+ url: request.url,
+ method: request.method,
+ headers: Object.fromEntries(request.headers.entries()),
+ cache: request.cache,
+ mode: request.mode,
+ credentials: request.credentials,
+ destination: request.destination,
+ integrity: request.integrity,
+ redirect: request.redirect,
+ referrer: request.referrer,
+ referrerPolicy: request.referrerPolicy,
+ body: await request.text(),
+ bodyUsed: request.bodyUsed,
+ keepalive: request.keepalive,
+ },
+ })
+
+ switch (clientMessage.type) {
+ case 'MOCK_RESPONSE': {
+ return respondWithMock(clientMessage.data)
+ }
+
+ case 'MOCK_NOT_FOUND': {
+ return passthrough()
+ }
+
+ case 'NETWORK_ERROR': {
+ const { name, message } = clientMessage.data
+ const networkError = new Error(message)
+ networkError.name = name
+
+ // Rejecting a "respondWith" promise emulates a network error.
+ throw networkError
+ }
+ }
+
+ return passthrough()
+}
+
+function sendToClient(client, message) {
+ return new Promise((resolve, reject) => {
+ const channel = new MessageChannel()
+
+ channel.port1.onmessage = (event) => {
+ if (event.data && event.data.error) {
+ return reject(event.data.error)
+ }
+
+ resolve(event.data)
+ }
+
+ client.postMessage(message, [channel.port2])
+ })
+}
+
+function sleep(timeMs) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, timeMs)
+ })
+}
+
+async function respondWithMock(response) {
+ await sleep(response.delay)
+ return new Response(response.body, response)
+}
diff --git a/src/Umbraco.Web.UI.Login/public/umbraco_logo_white.svg b/src/Umbraco.Web.UI.Login/public/umbraco_logo_white.svg
new file mode 100644
index 0000000000..3de8e82ed3
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/public/umbraco_logo_white.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Login/public/umbraco_logomark_white.svg b/src/Umbraco.Web.UI.Login/public/umbraco_logomark_white.svg
new file mode 100644
index 0000000000..9372e25d3e
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/public/umbraco_logomark_white.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Login/src/auth.element.ts b/src/Umbraco.Web.UI.Login/src/auth.element.ts
new file mode 100644
index 0000000000..96738588c7
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/auth.element.ts
@@ -0,0 +1,125 @@
+import { html, LitElement } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+import { ifDefined } from 'lit/directives/if-defined.js';
+import { until } from 'lit/directives/until.js';
+
+import { umbAuthContext } from './context/auth.context.js';
+import { umbLocalizationContext } from './external/localization/localization-context.js';
+
+@customElement('umb-auth')
+export default class UmbAuthElement extends LitElement {
+ #returnPath = '';
+
+ /**
+ * Disables the local login form and only allows external login providers.
+ *
+ * @attr disable-local-login
+ */
+ @property({ type: Boolean, attribute: 'disable-local-login' })
+ set disableLocalLogin(value: boolean) {
+ umbAuthContext.disableLocalLogin = value;
+ }
+
+ @property({ type: String, attribute: 'background-image' })
+ backgroundImage?: string;
+
+ @property({ type: String, attribute: 'logo-image' })
+ logoImage?: string;
+
+ @property({ type: Boolean, attribute: 'username-is-email' })
+ usernameIsEmail = false;
+
+ @property({ type: Boolean, attribute: 'allow-password-reset' })
+ allowPasswordReset = false;
+
+ @property({ type: Boolean, attribute: 'allow-user-invite' })
+ allowUserInvite = false;
+
+ @property({ type: String, attribute: 'return-url' })
+ set returnPath(value: string) {
+ this.#returnPath = value;
+ umbAuthContext.returnPath = this.returnPath;
+ }
+ get returnPath() {
+ // Check if there is a ?redir querystring or else return the returnUrl attribute
+ return new URLSearchParams(window.location.search).get('returnPath') || this.#returnPath;
+ }
+
+ /**
+ * Override the default flow.
+ */
+ protected flow?: 'mfa' | 'reset-password' | 'invite-user';
+
+ constructor() {
+ super();
+ this.classList.add('uui-text');
+ this.classList.add('uui-font');
+
+ (this as unknown as EventTarget).addEventListener('umb-login-flow', (e) => {
+ if (e instanceof CustomEvent) {
+ this.flow = e.detail.flow || undefined;
+ }
+ this.requestUpdate();
+ });
+ }
+
+ render() {
+ return html`
+
+ ${this._renderFlowAndStatus()}
+
+ `;
+ }
+
+ private _renderFlowAndStatus() {
+ const searchParams = new URLSearchParams(window.location.search);
+ let flow = this.flow || searchParams.get('flow')?.toLowerCase();
+ const status = searchParams.get('status');
+
+ if (status === 'resetCodeExpired') {
+ return html`
+ `;
+ }
+
+ if (flow === 'invite-user' && status === 'false') {
+ return html`
+ `;
+ }
+
+ // validate
+ if (flow) {
+ if (flow === 'mfa' && !umbAuthContext.isMfaEnabled) {
+ flow = undefined;
+ }
+ }
+
+ switch (flow) {
+ case 'mfa':
+ return html`
`;
+ case 'reset':
+ return html`
`;
+ case 'reset-password':
+ return html`
`;
+ case 'invite-user':
+ return html`
`;
+
+ default:
+ return html`
+
+
+ `;
+ }
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-auth': UmbAuthElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/back-to-login-button.element.ts b/src/Umbraco.Web.UI.Login/src/components/back-to-login-button.element.ts
new file mode 100644
index 0000000000..adf773f66a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/back-to-login-button.element.ts
@@ -0,0 +1,58 @@
+import { CSSResultGroup, LitElement, css, html } from 'lit';
+import { customElement } from 'lit/decorators.js';
+
+@customElement('umb-back-to-login-button')
+export default class UmbBackToLoginButtonElement extends LitElement {
+ render() {
+ return html`
+
+ `;
+ }
+
+ #handleClick() {
+ this.dispatchEvent(new CustomEvent('umb-login-flow', {composed: true, detail: {flow: 'login'}}));
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ :host {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ button {
+ cursor: pointer;
+ background: none;
+ border: 0;
+ height: 1rem;
+ color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */
+ gap: var(--uui-size-space-1);
+ align-self: center;
+ text-decoration: none;
+ display: inline-flex;
+ line-height: 1;
+ font-size: 14px;
+ font-family: var(--uui-font-family);
+ }
+ button svg {
+ width: 1rem;
+ }
+ button:hover {
+ color: var(--uui-color-interactive-emphasis);
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-back-to-login-button': UmbBackToLoginButtonElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/external-login-provider.element.ts b/src/Umbraco.Web.UI.Login/src/components/external-login-provider.element.ts
new file mode 100644
index 0000000000..cdab26115e
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/external-login-provider.element.ts
@@ -0,0 +1,206 @@
+import type { InterfaceColor, InterfaceLook } from '@umbraco-ui/uui';
+import { css, CSSResultGroup, html, LitElement, nothing } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+import { until } from 'lit/directives/until.js';
+
+import { loadCustomView, renderCustomView } from '../utils/load-custom-view.function.js';
+import { umbLocalizationContext } from '../external/localization/localization-context.js';
+
+type ExternalLoginCustomViewElement = HTMLElement & {
+ displayName: string;
+ providerName: string;
+ externalLoginUrl: string;
+};
+
+/**
+ * This elements represents a single external login provider and should be slotted into the
element.
+ *
+ * @element umb-external-login-provider
+ */
+@customElement('umb-external-login-provider')
+export class UmbExternalLoginProviderElement extends LitElement {
+ /**
+ * Gets or sets the path to the module that should be loaded as the custom view.
+ * The module should export a default class that extends HTMLElement.
+ *
+ * Setting this property will cause the default view to be hidden and the custom view to be loaded.
+ * The icon, button look and button color will be ignored.
+ *
+ * @example App_Plugins/MyPackage/MyCustomLoginView.js
+ * @attr custom-view
+ */
+ @property({ attribute: 'custom-view' })
+ customView?: string;
+
+ /**
+ * Gets or sets the display name of the provider.
+ *
+ * @attr display-name
+ * @example Google
+ */
+ @property({ attribute: 'display-name' })
+ displayName = '';
+
+ /**
+ * Gets or sets the name of the provider (otherwise known as authentication type).
+ *
+ * @attr provider-name
+ * @example Umbraco.Google
+ */
+ @property({ attribute: 'provider-name' })
+ providerName = '';
+
+ /**
+ * Gets or sets the url to the external login provider.
+ *
+ * @attr external-login-url
+ * @example /umbraco/ExternalLogin
+ */
+ @property({ attribute: 'external-login-url' })
+ get externalLoginUrl() {
+ return this.#externalLoginUrl;
+ }
+ set externalLoginUrl(value: string) {
+ const tempUrl = new URL(value, window.location.origin);
+ const searchParams = new URLSearchParams(tempUrl.search);
+ tempUrl.searchParams.append('redirectUrl', decodeURIComponent(searchParams.get('returnPath') ?? ''));
+ this.#externalLoginUrl = tempUrl.pathname + tempUrl.search;
+ }
+
+ /**
+ * Gets or sets the icon to display next to the provider name.
+ * This should be the name of an icon in the Umbraco Backoffice icon set.
+ *
+ * @attr icon
+ * @example icon-google-fill
+ * @default icon-lock
+ */
+ @property({ attribute: 'icon' })
+ icon = 'icon-lock';
+
+ /**
+ * Gets or sets the look of the underlying uui-button.
+ *
+ * @attr button-look
+ * @example outline
+ * @default outline
+ * @see https://uui.umbraco.com/?path=/story/uui-button--looks-and-colors
+ */
+ @property({ attribute: 'button-look' })
+ buttonLook: InterfaceLook = 'outline';
+
+ /**
+ * Gets or sets the color of the underlying uui-button.
+ *
+ * @attr button-color
+ * @example danger
+ * @default default
+ * @see https://uui.umbraco.com/?path=/story/uui-button--looks-and-colors
+ */
+ @property({ attribute: 'button-color' })
+ buttonColor: InterfaceColor = 'default';
+
+ #externalLoginUrl = '';
+
+ protected render() {
+ return this.customView
+ ? until(this.renderCustomView(), html``)
+ : this.renderDefaultView();
+ }
+
+ protected renderDefaultView() {
+ return html`
+
+ `;
+ }
+
+ protected async renderCustomView() {
+ try {
+ if (!this.customView) return;
+
+ const customView = await loadCustomView(this.customView);
+
+ if (typeof customView === 'object') {
+ customView.displayName = this.displayName;
+ customView.providerName = this.providerName;
+ customView.externalLoginUrl = this.externalLoginUrl;
+ }
+
+ return renderCustomView(customView);
+ } catch (error: unknown) {
+ console.group('[External login] Failed to load custom view');
+ console.log('Provider name', this.providerName);
+ console.log('Element reference', this);
+ console.log('Custom view', this.customView);
+ console.error('Failed to load custom view:', error);
+ console.groupEnd();
+ }
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ #defaultView uui-button {
+ width: 100%;
+ --uui-button-padding-top-factor: 1.5;
+ --uui-button-padding-bottom-factor: 1.5;
+ }
+ #defaultView uui-button div {
+ /* TODO: Remove this when uui-button has setting for aligning content */
+ position: absolute;
+ left: 9px;
+ margin: auto;
+ text-align: left;
+ top: 50%;
+ transform: translateY(-50%);
+ }
+ #defaultView button {
+ font-size: var(--uui-button-font-size);
+ border: 1px solid var(--uui-color-border);
+ border-radius: var(--uui-border-radius);
+ width: 100%;
+ padding: 9px;
+ text-align: left;
+ background-color: var(--uui-color-surface);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: var(--uui-size-space-2);
+ box-sizing: border-box;
+
+ line-height: 1.1; /* makes the text vertically centered */
+ color: var(--uui-color-interactive);
+ }
+
+ #defaultView button:hover {
+ color: var(--uui-color-interactive-emphasis);
+ border-color: var(--uui-color-border-standalone);
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-external-login-provider': UmbExternalLoginProviderElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/layouts/auth-layout.element.ts b/src/Umbraco.Web.UI.Login/src/components/layouts/auth-layout.element.ts
new file mode 100644
index 0000000000..a76e032ffa
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/layouts/auth-layout.element.ts
@@ -0,0 +1,80 @@
+import { css, CSSResultGroup, html, LitElement, nothing } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+import { styleMap } from 'lit/directives/style-map.js';
+
+@customElement('umb-auth-layout')
+export class UmbAuthLayoutElement extends LitElement {
+ @property({ attribute: 'background-image' })
+ backgroundImage?: string;
+
+ @property({ attribute: 'logo-image' })
+ logoImage?: string;
+
+ render() {
+ return html`
+
+
+ ${this.logoImage ? html`` : nothing}
+
+
+ `;
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ #background {
+ position: fixed;
+ overflow: hidden;
+ background-position: 50%;
+ background-repeat: no-repeat;
+ background-size: cover;
+ width: 100vw;
+ height: 100vh;
+ }
+
+ #logo {
+ position: fixed;
+ top: var(--uui-size-space-5);
+ left: var(--uui-size-space-5);
+ height: 30px;
+ }
+
+ #logo img {
+ height: 100%;
+ }
+
+ #container {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100vw;
+ height: 100vh;
+ }
+
+ #box {
+ width: 500px;
+ padding: var(--uui-size-layout-3);
+ background-color: var(--uui-color-surface-alt);
+ box-sizing: border-box;
+ box-shadow: var(--uui-shadow-depth-5);
+ border-radius: calc(var(--uui-border-radius) * 2);
+ }
+
+ #email,
+ #password {
+ width: 100%;
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-auth-layout': UmbAuthLayoutElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/layouts/confirmation-layout.element.ts b/src/Umbraco.Web.UI.Login/src/components/layouts/confirmation-layout.element.ts
new file mode 100644
index 0000000000..4f8b3bed30
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/layouts/confirmation-layout.element.ts
@@ -0,0 +1,61 @@
+import { CSSResultGroup, LitElement, css, html } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+
+@customElement('umb-confirmation-layout')
+export default class UmbConfirmationLayoutElement extends LitElement {
+ @property({ type: String })
+ header = '';
+
+ @property({ type: String })
+ message = '';
+
+ render() {
+ return html`
+
+
+
+
+
+ `;
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ :host {
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-layout-1);
+ }
+ #header {
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-space-5);
+ }
+ #header span {
+ color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */
+ font-size: 14px;
+ }
+ #header h2 {
+ margin: 0px;
+ font-weight: bold;
+ font-size: 1.4rem;
+ }
+ uui-button {
+ width: 100%;
+ margin-top: var(--uui-size-space-5);
+ --uui-button-padding-top-factor: 1.5;
+ --uui-button-padding-bottom-factor: 1.5;
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-confirmation-layout': UmbConfirmationLayoutElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/layouts/error-layout.element.ts b/src/Umbraco.Web.UI.Login/src/components/layouts/error-layout.element.ts
new file mode 100644
index 0000000000..37fe931e9a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/layouts/error-layout.element.ts
@@ -0,0 +1,59 @@
+import { CSSResultGroup, LitElement, css, html } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+
+@customElement('umb-error-layout')
+export default class UmbErrorLayoutElement extends LitElement {
+ @property({ type: String })
+ header = '';
+
+ @property({ type: String })
+ message = '';
+
+ render() {
+ return html`
+
+
+
+ `;
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ :host {
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-layout-1);
+ }
+ #header {
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-space-5);
+ }
+ #header span {
+ color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */
+ font-size: 14px;
+ }
+ #header h2 {
+ margin: 0;
+ font-weight: bold;
+ font-size: 1.4rem;
+ }
+ ::slotted(uui-button) {
+ width: 100%;
+ margin-top: var(--uui-size-space-5);
+ --uui-button-padding-top-factor: 1.5;
+ --uui-button-padding-bottom-factor: 1.5;
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-error-layout': UmbErrorLayoutElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/layouts/external-login-providers-layout.element.ts b/src/Umbraco.Web.UI.Login/src/components/layouts/external-login-providers-layout.element.ts
new file mode 100644
index 0000000000..ac28eaf6ec
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/layouts/external-login-providers-layout.element.ts
@@ -0,0 +1,77 @@
+import { css, CSSResultGroup, html, LitElement, nothing } from 'lit';
+import { customElement, property, queryAssignedElements } from 'lit/decorators.js';
+
+@customElement('umb-external-login-providers-layout')
+export class UmbExternalLoginProvidersLayoutElement extends LitElement {
+ @property({ type: Boolean, attribute: 'divider' })
+ showDivider = true;
+
+ @queryAssignedElements({ flatten: true })
+ protected slottedElements?: HTMLElement[];
+
+ firstUpdated() {
+ !!this.slottedElements?.length ? this.toggleAttribute('empty', false) : this.toggleAttribute('empty', true);
+ }
+
+ render() {
+ return html`
+ ${this.showDivider ? html` Or
` : nothing}
+
+
+
+ `;
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ :host {
+ margin-top: 16px;
+ display: flex;
+ flex-direction: column;
+ }
+
+ :host([empty]) {
+ display: none;
+ }
+
+ slot {
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-space-4);
+ }
+
+ #divider {
+ width: 100%;
+ text-align: center;
+ color: var(--uui-color-interactive);
+ position: relative;
+ z-index: 0;
+ margin-bottom: 16px;
+ }
+
+ #divider span {
+ background-color: var(--uui-color-surface-alt);
+ padding: 0 9px;
+ text-transform: capitalize;
+ }
+
+ #divider::before {
+ content: '';
+ display: block;
+ width: 100%;
+ height: 1px;
+ background-color: var(--uui-color-border);
+ position: absolute;
+ top: calc(50% + 1px);
+ transform: translateY(-50%);
+ z-index: -1;
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-external-login-providers-layout': UmbExternalLoginProvidersLayoutElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/layouts/new-password-layout.element.ts b/src/Umbraco.Web.UI.Login/src/components/layouts/new-password-layout.element.ts
new file mode 100644
index 0000000000..4054a78630
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/layouts/new-password-layout.element.ts
@@ -0,0 +1,202 @@
+import type { UUIButtonState, UUIInputPasswordElement } from '@umbraco-ui/uui';
+import { CSSResultGroup, LitElement, css, html, nothing } from 'lit';
+import { customElement, property, query, state } from 'lit/decorators.js';
+import { until } from 'lit/directives/until.js';
+
+import { umbAuthContext } from '../../context/auth.context.js';
+import { umbLocalizationContext } from '../../external/localization/localization-context.js';
+
+@customElement('umb-new-password-layout')
+export default class UmbNewPasswordLayoutElement extends LitElement {
+ @query('#password')
+ passwordElement!: UUIInputPasswordElement;
+
+ @query('#confirmPassword')
+ confirmPasswordElement!: UUIInputPasswordElement;
+
+ @property()
+ state: UUIButtonState = undefined;
+
+ @property()
+ error: string = '';
+
+ @property()
+ userId: any;
+
+ @property()
+ userName?: string;
+
+ @state()
+ passwordConfig?: {
+ allowManuallyChangingPassword: boolean;
+ minNonAlphaNumericChars: number;
+ minPasswordLength: number;
+ };
+
+ protected async firstUpdated(_changedProperties: any) {
+ super.firstUpdated(_changedProperties);
+
+ if (this.userId) {
+ const response = await umbAuthContext.getPasswordConfig(this.userId);
+ this.passwordConfig = response.data;
+ }
+ }
+
+ async #onSubmit(event: Event) {
+ event.preventDefault();
+ if (!this.passwordConfig) return;
+ const form = event.target as HTMLFormElement;
+
+ this.passwordElement.setCustomValidity('');
+ this.confirmPasswordElement.setCustomValidity('');
+
+ if (!form) return;
+ if (!form.checkValidity()) return;
+
+ const formData = new FormData(form);
+ const password = formData.get('password') as string;
+ const passwordConfirm = formData.get('confirmPassword') as string;
+
+ let passwordIsInvalid = false;
+
+ if (this.passwordConfig.minPasswordLength > 0 && password.length < this.passwordConfig.minPasswordLength) {
+ passwordIsInvalid = true;
+ }
+
+ if (this.passwordConfig.minNonAlphaNumericChars > 0) {
+ const nonAlphaNumericChars = password.replace(/[a-zA-Z0-9]/g, '').length; //TODO: How should we check for non-alphanumeric chars?
+ if (nonAlphaNumericChars < this.passwordConfig?.minNonAlphaNumericChars) {
+ passwordIsInvalid = true;
+ }
+ }
+
+ if (passwordIsInvalid) {
+ const passwordValidityText = await umbLocalizationContext.localize('errorHandling_errorInPasswordFormat', [this.passwordConfig.minPasswordLength, this.passwordConfig.minNonAlphaNumericChars], "The password doesn't meet the minimum requirements!");
+ this.passwordElement.setCustomValidity(passwordValidityText);
+ return;
+ }
+
+ if (password !== passwordConfirm) {
+ const passwordValidityText = await umbLocalizationContext.localize('user_passwordMismatch', undefined, "The confirmed password doesn't match the new password!");
+ this.confirmPasswordElement.setCustomValidity(passwordValidityText);
+ return;
+ }
+
+ this.dispatchEvent(new CustomEvent('submit', { detail: { password } }));
+ }
+
+ renderHeader() {
+ if (this.userName) {
+ return html`
+ Hi, ${this.userName}
+ Welcome to Umbraco! Just need to get your password setup and then you're good to go
+ `;
+ } else {
+ return html`
+ New password
+ Please provide a new password.
+ `;
+ }
+ }
+
+ render() {
+ return html`
+
+
+
+
+
+ `;
+ }
+
+ #renderErrorMessage() {
+ if (!this.error || this.state !== 'failed') return nothing;
+
+ return html`${this.error}`;
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ #header {
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-space-5);
+ }
+ #header span {
+ color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */
+ font-size: 14px;
+ }
+ #header h2 {
+ margin: 0px;
+ font-weight: bold;
+ font-size: 1.4rem;
+ }
+ form {
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-space-5);
+ }
+ uui-form-layout-item {
+ margin: 0;
+ }
+ h2 {
+ margin: 0px;
+ font-weight: 600;
+ font-size: 1.4rem;
+ margin-bottom: var(--uui-size-space-4);
+ }
+ uui-input-password {
+ width: 100%;
+ }
+ uui-button {
+ width: 100%;
+ margin-top: var(--uui-size-space-5);
+ --uui-button-padding-top-factor: 1.5;
+ --uui-button-padding-bottom-factor: 1.5;
+ }
+ .text-danger {
+ color: var(--uui-color-danger-standalone);
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-new-password-layout': UmbNewPasswordLayoutElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/pages/invite.page.element.ts b/src/Umbraco.Web.UI.Login/src/components/pages/invite.page.element.ts
new file mode 100644
index 0000000000..a5bd23aae7
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/pages/invite.page.element.ts
@@ -0,0 +1,71 @@
+import type { UUIButtonState } from '@umbraco-ui/uui';
+import { LitElement, html, nothing } from 'lit';
+import { customElement, state } from 'lit/decorators.js';
+import { until } from 'lit/directives/until.js';
+
+import { umbAuthContext } from '../../context/auth.context.js';
+import { umbLocalizationContext } from '../../external/localization/localization-context.js';
+
+@customElement('umb-invite-page')
+export default class UmbInvitePageElement extends LitElement {
+ @state()
+ state: UUIButtonState = undefined;
+
+ @state()
+ error = '';
+
+ @state()
+ invitedUser?: any;
+
+ protected async firstUpdated(_changedProperties: any) {
+ super.firstUpdated(_changedProperties);
+
+ const response = await umbAuthContext.getInvitedUser();
+
+ if (!response.user?.id) {
+ // The login page should already have redirected the user to an error page. They should never get here.
+ this.error = 'No invited user found';
+ return;
+ }
+
+ this.invitedUser = response.user;
+ }
+
+ async #onSubmit(event: CustomEvent) {
+ event.preventDefault();
+ const password = event.detail.password;
+
+ if (!password) return;
+
+ this.state = 'waiting';
+ const response = await umbAuthContext.newInvitedUserPassword(password);
+
+ if (response.error) {
+ this.error = response.error;
+ this.state = 'failed';
+ return;
+ }
+
+ this.state = 'success';
+ window.location.href = umbAuthContext.returnPath;
+ }
+
+ render() {
+ return this.invitedUser
+ ? html``
+ : this.error
+ ? html``
+ : nothing;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-invite-page': UmbInvitePageElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/pages/login.page.element.ts b/src/Umbraco.Web.UI.Login/src/components/pages/login.page.element.ts
new file mode 100644
index 0000000000..427aefa31c
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/pages/login.page.element.ts
@@ -0,0 +1,254 @@
+import type { UUIButtonState } from '@umbraco-ui/uui';
+import { css, CSSResultGroup, html, LitElement, nothing } from 'lit';
+import { customElement, property, state } from 'lit/decorators.js';
+import { when } from 'lit/directives/when.js';
+import { until } from 'lit/directives/until.js';
+
+import { umbAuthContext } from '../../context/auth.context.js';
+import { umbLocalizationContext } from '../../external/localization/localization-context.js';
+
+@customElement('umb-login-page')
+export default class UmbLoginPageElement extends LitElement {
+
+ @property({ type: Boolean, attribute: 'username-is-email' })
+ usernameIsEmail = false;
+
+ @property({ type: Boolean, attribute: 'allow-password-reset' })
+ allowPasswordReset = false;
+
+ @state()
+ private _loginState: UUIButtonState = undefined;
+
+ @state()
+ private _loginError = '';
+
+ @state()
+ private get disableLocalLogin() {
+ return umbAuthContext.disableLocalLogin;
+ }
+
+ #handleSubmit = async (e: SubmitEvent) => {
+ e.preventDefault();
+
+ const form = e.target as HTMLFormElement;
+ if (!form) return;
+
+ if (!form.checkValidity()) return;
+
+ const formData = new FormData(form);
+
+ const username = formData.get('email') as string;
+ const password = formData.get('password') as string;
+ const persist = formData.has('persist');
+
+ this._loginState = 'waiting';
+
+ const response = await umbAuthContext.login({
+ username,
+ password,
+ persist,
+ });
+
+ this._loginError = response.error || '';
+ this._loginState = response.error ? 'failed' : 'success';
+
+ // Check for 402 status code indicating that MFA is required
+ if (response.status === 402) {
+ umbAuthContext.isMfaEnabled = true;
+ if (response.twoFactorView) {
+ umbAuthContext.twoFactorView = response.twoFactorView;
+ }
+
+ this.dispatchEvent(new CustomEvent('umb-login-flow', { composed: true, detail: { flow: 'mfa' }}));
+ return;
+ }
+
+ if (response.error) {
+ this.dispatchEvent(new CustomEvent('umb-login-failed', { bubbles: true, composed: true, detail: response }));
+ return;
+ }
+
+ const returnPath = umbAuthContext.returnPath;
+
+ if (returnPath) {
+ location.href = returnPath;
+ }
+
+ this.dispatchEvent(new CustomEvent('umb-login-success', { bubbles: true, composed: true, detail: response.data }));
+ };
+
+ get #greetingLocalizationKey() {
+ return [
+ 'login_greeting0',
+ 'login_greeting1',
+ 'login_greeting2',
+ 'login_greeting3',
+ 'login_greeting4',
+ 'login_greeting5',
+ 'login_greeting6',
+ ][new Date().getDay()];
+ }
+
+ render() {
+ return html`
+
+
+
+
+ ${this.disableLocalLogin
+ ? nothing
+ : html`
+
+
+
+ `}
+
+
+
+ `;
+ }
+
+ #renderErrorMessage() {
+ if (!this._loginError || this._loginState !== 'failed') return nothing;
+
+ return html`${this._loginError}`;
+ }
+
+ #handleForgottenPassword() {
+ this.dispatchEvent(new CustomEvent('umb-login-flow', { composed: true, detail: { flow: 'reset' }}));
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ :host {
+ display: flex;
+ flex-direction: column;
+ }
+
+ #greeting {
+ text-align: center;
+ font-weight: 600;
+ font-size: 1.4rem;
+ margin: 0 0 var(--uui-size-space-6);
+ }
+
+ form {
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-space-5);
+ }
+
+ uui-form-layout-item {
+ margin: 0;
+ }
+
+ uui-input,
+ uui-input-password {
+ width: 100%;
+ border-radius: var(--uui-border-radius);
+ }
+
+ #umb-login-button {
+ width: 100%;
+ --uui-button-padding-top-factor: 1.5;
+ --uui-button-padding-bottom-factor: 1.5;
+ }
+
+ #forgot-password {
+ cursor: pointer;
+ background: none;
+ border: 0;
+ height: 1rem;
+ color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */
+ gap: var(--uui-size-space-1);
+ align-self: center;
+ text-decoration: none;
+ display: inline-flex;
+ line-height: 1;
+ font-size: 14px;
+ font-family: var(--uui-font-family);
+ }
+
+ #forgot-password:hover {
+ color: var(--uui-color-interactive-emphasis);
+ }
+
+ .text-danger {
+ color: var(--uui-color-danger-standalone);
+ }
+
+ #secondary-actions {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-login-page': UmbLoginPageElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/pages/mfa.page.element.ts b/src/Umbraco.Web.UI.Login/src/components/pages/mfa.page.element.ts
new file mode 100644
index 0000000000..2e6b59c67b
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/pages/mfa.page.element.ts
@@ -0,0 +1,241 @@
+import type { UUIButtonState, UUIInputElement } from '@umbraco-ui/uui';
+import { LitElement, css, html, nothing } from 'lit';
+import { customElement, state } from 'lit/decorators.js';
+import { until } from 'lit/directives/until.js';
+import { umbAuthContext } from '../../context/auth.context.js';
+import { umbLocalizationContext } from '../../external/localization/localization-context.js';
+import { loadCustomView, renderCustomView } from '../../utils/load-custom-view.function.js';
+
+type MfaCustomViewElement = HTMLElement & {
+ providers: string[];
+};
+
+@customElement('umb-mfa-page')
+export default class UmbMfaPageElement extends LitElement {
+ @state()
+ protected providers: Array<{ name: string; value: string; selected: boolean }> = [];
+
+ @state()
+ private loading = true;
+
+ @state()
+ private buttonState?: UUIButtonState;
+
+ @state()
+ private error: string | null = null;
+
+ constructor() {
+ super();
+ this.#loadProviders();
+ }
+
+ async #loadProviders() {
+ try {
+ const response = await umbAuthContext.getMfaProviders();
+ this.providers = response.providers.map((provider) => ({ name: provider, value: provider, selected: false }));
+
+ if (this.providers.length) {
+ this.providers[0].selected = true;
+ }
+
+ if (response.error) {
+ this.error = response.error;
+ }
+ } catch (e) {
+ if (e instanceof Error) {
+ this.error = e.message ?? 'Unknown error';
+ } else {
+ this.error = 'Unknown error';
+ }
+ this.providers = [];
+ }
+ this.loading = false;
+ }
+
+ private async handleSubmit(e: SubmitEvent) {
+ e.preventDefault();
+
+ this.error = null;
+
+ const form = e.target as HTMLFormElement;
+ if (!form) return;
+
+ const codeInput = form.elements.namedItem('2facode') as UUIInputElement;
+
+ if (codeInput) {
+ codeInput.error = false;
+ codeInput.errorMessage = '';
+ }
+
+ if (!form.checkValidity()) return;
+
+ const formData = new FormData(form);
+
+ let provider = formData.get('provider') as string;
+
+ // If no provider given, use the first one (there probably is only one anyway)
+ if (!provider) {
+ provider = this.providers[0].value;
+ }
+
+ if (!provider) {
+ this.error = 'No provider selected';
+ return;
+ }
+
+ const code = formData.get('token') as string;
+
+ this.buttonState = 'waiting';
+
+ try {
+ const response = await umbAuthContext.validateMfaCode(code, provider);
+ if (response.error) {
+ if (codeInput) {
+ codeInput.error = true;
+ codeInput.errorMessage = response.error;
+ } else {
+ this.error = response.error;
+ }
+ this.buttonState = 'failed';
+ return;
+ }
+
+ this.buttonState = 'success';
+
+ const returnPath = umbAuthContext.returnPath;
+ if (returnPath) {
+ location.href = returnPath;
+ }
+
+ this.dispatchEvent(new CustomEvent('umb-login-success', { bubbles: true, composed: true }));
+ } catch (e) {
+ if (e instanceof Error) {
+ this.error = e.message ?? 'Unknown error';
+ } else {
+ this.error = 'Unknown error';
+ }
+ this.buttonState = 'failed';
+ this.dispatchEvent(new CustomEvent('umb-login-failed', { bubbles: true, composed: true, detail: e }));
+ }
+ }
+
+ protected renderDefaultView() {
+ return html`
+
+
+
+ `;
+ }
+
+ protected async renderCustomView() {
+ const view = umbAuthContext.twoFactorView;
+ if (!view) return nothing;
+
+ try {
+ const customView = await loadCustomView(view);
+ if (typeof customView === 'object') {
+ customView.providers = this.providers.map((provider) => provider.value);
+ }
+ return renderCustomView(customView);
+ } catch (e) {
+ const error = e instanceof Error ? e.message : 'Unknown error';
+ console.group('[MFA login] Failed to load custom view');
+ console.log('Element reference', this);
+ console.log('Custom view', view);
+ console.error('Failed to load custom view:', e);
+ console.groupEnd();
+ return html`${error}`;
+ }
+ }
+
+ protected render() {
+ return this.loading
+ ? html``
+ : umbAuthContext.twoFactorView
+ ? until(this.renderCustomView(), html``)
+ : this.renderDefaultView();
+ }
+
+ private onGoBack() {
+ this.dispatchEvent(new CustomEvent('umb-login-flow', { composed: true, detail: { flow: undefined } }));
+ }
+
+ static styles = [
+ css`
+ .text-danger {
+ color: var(--uui-color-danger-standalone);
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-mfa-page': UmbMfaPageElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/pages/new-password.page.element.ts b/src/Umbraco.Web.UI.Login/src/components/pages/new-password.page.element.ts
new file mode 100644
index 0000000000..bc8f44b1ac
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/pages/new-password.page.element.ts
@@ -0,0 +1,87 @@
+import type { UUIButtonState, UUIInputPasswordElement } from '@umbraco-ui/uui';
+import { LitElement, html, nothing } from 'lit';
+import { customElement, query, state } from 'lit/decorators.js';
+import { until } from 'lit/directives/until.js';
+
+import { umbAuthContext } from '../../context/auth.context.js';
+import { umbLocalizationContext } from '../../external/localization/localization-context.js';
+
+@customElement('umb-new-password-page')
+export default class UmbNewPasswordPageElement extends LitElement {
+ @query('#confirmPassword')
+ confirmPasswordElement!: UUIInputPasswordElement;
+
+ @state()
+ state: UUIButtonState = undefined;
+
+ @state()
+ page: 'new' | 'done' | 'error' = 'new';
+
+ @state()
+ error = '';
+
+ @state()
+ userId: string | null = null;
+
+ @state()
+ resetCode: string | null = null;
+
+ constructor() {
+ super();
+
+ const urlParams = new URLSearchParams(window.location.search);
+ this.resetCode = urlParams.get('resetCode');
+ this.userId = urlParams.get('userId');
+
+ if (!this.userId || !this.resetCode) {
+ this.page = 'error';
+ }
+ }
+
+ async #onSubmit(event: CustomEvent) {
+ event.preventDefault();
+ const urlParams = new URLSearchParams(window.location.search);
+ const resetCode = urlParams.get('resetCode');
+ const userId = urlParams.get('userId');
+ const password = event.detail.password;
+
+ if (!resetCode || !userId) return;
+
+ this.state = 'waiting';
+ const response = await umbAuthContext.newPassword(password, resetCode, userId);
+ this.state = response.status === 200 ? 'success' : 'failed';
+ this.page = response.status === 200 ? 'done' : 'new';
+ this.error = response.error || '';
+ }
+
+ #renderRoutes() {
+ switch (this.page) {
+ case 'new':
+ return html``;
+ case 'error':
+ return html`
+ `;
+ case 'done':
+ return html`
+ `;
+ }
+ }
+
+ render() {
+ return this.userId && this.resetCode ? this.#renderRoutes() : nothing;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-new-password-page': UmbNewPasswordPageElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/components/pages/reset-password.page.element.ts b/src/Umbraco.Web.UI.Login/src/components/pages/reset-password.page.element.ts
new file mode 100644
index 0000000000..dc77010105
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/components/pages/reset-password.page.element.ts
@@ -0,0 +1,155 @@
+import type { UUIButtonState } from '@umbraco-ui/uui';
+import { CSSResultGroup, LitElement, css, html, nothing } from 'lit';
+import { customElement, state } from 'lit/decorators.js';
+import { until } from 'lit/directives/until.js';
+
+import { umbAuthContext } from '../../context/auth.context.js';
+import { umbLocalizationContext } from '../../external/localization/localization-context.js';
+
+@customElement('umb-reset-password-page')
+export default class UmbResetPasswordPageElement extends LitElement {
+ @state()
+ resetCallState: UUIButtonState = undefined;
+
+ @state()
+ error = '';
+
+ #handleResetSubmit = async (e: SubmitEvent) => {
+ e.preventDefault();
+ const form = e.target as HTMLFormElement;
+
+ if (!form) return;
+ if (!form.checkValidity()) return;
+
+ const formData = new FormData(form);
+ const username = formData.get('email') as string;
+
+ this.resetCallState = 'waiting';
+ const response = await umbAuthContext.resetPassword(username);
+ this.resetCallState = response.status === 200 ? 'success' : 'failed';
+ this.error = response.error || '';
+ };
+
+ #renderResetPage() {
+ return html`
+
+
+
+
+
+ `;
+ }
+
+ #renderErrorMessage() {
+ if (!this.error || this.resetCallState !== 'failed') return nothing;
+
+ return html`${this.error}`;
+ }
+
+ #renderConfirmationPage() {
+ return html`
+
+
+ `;
+ }
+
+ render() {
+ return this.resetCallState === 'success' ? this.#renderConfirmationPage() : this.#renderResetPage();
+ }
+
+ static styles: CSSResultGroup = [
+ css`
+ #header {
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-space-5);
+ }
+ #header span {
+ color: var(--uui-color-text-alt); /* TODO Change to uui color when uui gets a muted text variable */
+ font-size: 14px;
+ }
+ #header h2 {
+ margin: 0px;
+ font-weight: bold;
+ font-size: 1.4rem;
+ }
+ form {
+ display: flex;
+ flex-direction: column;
+ gap: var(--uui-size-layout-2);
+ }
+ uui-form-layout-item {
+ margin: 0;
+ }
+ uui-input,
+ uui-input-password {
+ width: 100%;
+ border-radius: var(--uui-border-radius);
+ }
+ uui-input {
+ width: 100%;
+ }
+ uui-button {
+ width: 100%;
+ --uui-button-padding-top-factor: 1.5;
+ --uui-button-padding-bottom-factor: 1.5;
+ }
+
+ #resend {
+ display: inline-flex;
+ font-size: 14px;
+ align-self: center;
+ gap: var(--uui-size-space-1);
+ }
+
+ #resend a {
+ color: var(--uui-color-selected);
+ font-weight: 600;
+ text-decoration: none;
+ }
+ #resend a:hover {
+ color: var(--uui-color-interactive-emphasis);
+ }
+ `,
+ ];
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-reset-password-page': UmbResetPasswordPageElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/context/auth.context.ts b/src/Umbraco.Web.UI.Login/src/context/auth.context.ts
new file mode 100644
index 0000000000..4abd9441a3
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/context/auth.context.ts
@@ -0,0 +1,58 @@
+import {
+ LoginRequestModel,
+ IUmbAuthContext,
+ LoginResponse,
+ ResetPasswordResponse,
+ ValidatePasswordResetCodeResponse,
+ NewPasswordResponse,
+ MfaProvidersResponse,
+} from '../types.js';
+import { UmbAuthRepository } from './auth.repository.js';
+
+export class UmbAuthContext implements IUmbAuthContext {
+ readonly supportsPersistLogin = false;
+ disableLocalLogin = false;
+
+ #authRepository = new UmbAuthRepository();
+
+ public returnPath = '';
+
+ async login(data: LoginRequestModel): Promise {
+ return this.#authRepository.login(data);
+ }
+
+ async resetPassword(username: string): Promise {
+ return this.#authRepository.resetPassword(username);
+ }
+
+ async validatePasswordResetCode(userId: string, resetCode: string): Promise {
+ return this.#authRepository.validatePasswordResetCode(userId, resetCode);
+ }
+
+ async newPassword(password: string, resetCode: string, userId: string): Promise {
+ const userIdAsNumber = Number.parseInt(userId);
+ return this.#authRepository.newPassword(password, resetCode, userIdAsNumber);
+ }
+
+ async newInvitedUserPassword(password: string): Promise {
+ return this.#authRepository.newInvitedUserPassword(password);
+ }
+
+ async getPasswordConfig(userId: string): Promise {
+ return this.#authRepository.getPasswordConfig(userId);
+ }
+
+ async getInvitedUser(): Promise {
+ return this.#authRepository.getInvitedUser();
+ }
+
+ getMfaProviders(): Promise {
+ return this.#authRepository.getMfaProviders();
+ }
+
+ validateMfaCode(code: string, provider: string): Promise {
+ return this.#authRepository.validateMfaCode(code, provider);
+ }
+}
+
+export const umbAuthContext = new UmbAuthContext() as IUmbAuthContext;
diff --git a/src/Umbraco.Web.UI.Login/src/context/auth.repository.ts b/src/Umbraco.Web.UI.Login/src/context/auth.repository.ts
new file mode 100644
index 0000000000..45f44f6781
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/context/auth.repository.ts
@@ -0,0 +1,262 @@
+import type {
+ LoginRequestModel,
+ LoginResponse,
+ MfaProvidersResponse,
+ ResetPasswordResponse,
+ ValidatePasswordResetCodeResponse,
+} from '../types.js';
+import { umbLocalizationContext } from '../external/localization/localization-context.js';
+
+export class UmbAuthRepository {
+ readonly #authURL = 'backoffice/umbracoapi/authentication/postlogin';
+
+ public async login(data: LoginRequestModel): Promise {
+ try {
+ const request = new Request(this.#authURL, {
+ method: 'POST',
+ body: JSON.stringify({
+ username: data.username,
+ password: data.password,
+ rememberMe: data.persist,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ const text = await response.text();
+ const responseData = JSON.parse(this.#removeAngularJSResponseData(text));
+
+ return {
+ status: response.status,
+ error: response.ok ? undefined : await this.#getErrorText(response),
+ data: responseData,
+ twoFactorView: responseData?.twoFactorView,
+ };
+ } catch (error) {
+ return {
+ status: 500,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ };
+ }
+ }
+
+ public async resetPassword(email: string): Promise {
+ const request = new Request('backoffice/umbracoapi/authentication/PostRequestPasswordReset', {
+ method: 'POST',
+ body: JSON.stringify({
+ email,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ return {
+ status: response.status,
+ error: response.ok ? undefined : await this.#getErrorText(response),
+ };
+ }
+
+ public async validatePasswordResetCode(user: string, code: string): Promise {
+ const request = new Request('backoffice/umbracoapi/authentication/validatepasswordresetcode', {
+ method: 'POST',
+ body: JSON.stringify({
+ userId: user,
+ resetCode: code,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ return {
+ status: response.status,
+ error: response.ok ? undefined : await this.#getErrorText(response),
+ };
+ }
+
+ public async newPassword(password: string, resetCode: string, userId: number): Promise {
+ const request = new Request('backoffice/umbracoapi/authentication/PostSetPassword', {
+ method: 'POST',
+ body: JSON.stringify({
+ password,
+ resetCode,
+ userId,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ return {
+ status: response.status,
+ error: response.ok ? undefined : await this.#getErrorText(response),
+ };
+ }
+
+ public async newInvitedUserPassword(newPassWord: string): Promise {
+ const request = new Request('backoffice/umbracoapi/authentication/PostSetInvitedUserPassword', {
+ method: 'POST',
+ body: JSON.stringify({
+ newPassWord,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ return {
+ status: response.status,
+ error: response.ok ? undefined : await this.#getErrorText(response),
+ };
+ }
+
+ public async getPasswordConfig(userId: string): Promise {
+ //TODO: Add type
+ const request = new Request(`backoffice/umbracoapi/authentication/GetPasswordConfig?userId=${userId}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ // Check if response contains AngularJS response data
+ if (response.ok) {
+ let text = await response.text();
+ text = this.#removeAngularJSResponseData(text);
+ const data = JSON.parse(text);
+
+ return {
+ status: response.status,
+ data,
+ };
+ }
+
+ return {
+ status: response.status,
+ error: response.ok ? undefined : this.#getErrorText(response),
+ };
+ }
+
+ public async getInvitedUser(): Promise {
+ //TODO: Add type
+ const request = new Request('backoffice/umbracoapi/authentication/GetCurrentInvitedUser', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ // Check if response contains AngularJS response data
+ if (response.ok) {
+ let text = await response.text();
+ text = this.#removeAngularJSResponseData(text);
+ const user = JSON.parse(text);
+
+ return {
+ status: response.status,
+ user,
+ };
+ }
+
+ return {
+ status: response.status,
+ error: this.#getErrorText(response),
+ };
+ }
+
+ public async getMfaProviders(): Promise {
+ const request = new Request('backoffice/umbracoapi/authentication/Get2faProviders', {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const response = await fetch(request);
+
+ // Check if response contains AngularJS response data
+ if (response.ok) {
+ let text = await response.text();
+ text = this.#removeAngularJSResponseData(text);
+ const providers = JSON.parse(text);
+
+ return {
+ status: response.status,
+ providers,
+ };
+ }
+
+ return {
+ status: response.status,
+ error: await this.#getErrorText(response),
+ providers: [],
+ };
+ }
+
+ public async validateMfaCode(code: string, provider: string): Promise {
+ const request = new Request('backoffice/umbracoapi/authentication/PostVerify2faCode', {
+ method: 'POST',
+ body: JSON.stringify({
+ code,
+ provider,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+
+ const response = await fetch(request);
+
+ if (response.ok) {
+ return {
+ status: response.status,
+ };
+ }
+
+ let text = await response.text();
+ text = this.#removeAngularJSResponseData(text);
+
+ const data = JSON.parse(text);
+
+ return {
+ status: response.status,
+ error: data.Message ?? 'An unknown error occurred.',
+ };
+ }
+
+ async #getErrorText(response: Response): Promise {
+ switch (response.status) {
+ case 400:
+ case 401:
+ return umbLocalizationContext.localize('login_userFailedLogin', undefined, "Oops! We couldn't log you in. Please check your credentials and try again.");
+
+ case 402:
+ return umbLocalizationContext.localize('login_2faText', undefined, 'You have enabled 2-factor authentication and must verify your identity.');
+
+ case 500:
+ return umbLocalizationContext.localize('errors_receivedErrorFromServer', undefined, 'Received error from server');
+
+ default:
+ return response.statusText ?? await umbLocalizationContext.localize('errors_receivedErrorFromServer', undefined, 'Received error from server')
+ }
+ }
+
+ /**
+ * AngularJS adds a prefix to the response data, which we need to remove
+ */
+ #removeAngularJSResponseData(text: string) {
+ if (text.startsWith(")]}',\n")) {
+ text = text.split('\n')[1];
+ }
+
+ return text;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/external.ts b/src/Umbraco.Web.UI.Login/src/external.ts
new file mode 100644
index 0000000000..f0f791b5e3
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/external.ts
@@ -0,0 +1,9 @@
+/**
+ * These are the public exports for the login UI.
+ * They are used by the Umbraco backoffice mainly to show external login providers.
+ */
+import '@umbraco-ui/uui-css/dist/uui-css.css';
+import '@umbraco-ui/uui';
+import './external/icon.registry.js';
+import './external/custom-view.element.js';
+import './external/localization/localize.element.js';
diff --git a/src/Umbraco.Web.UI.Login/src/external/custom-view.element.ts b/src/Umbraco.Web.UI.Login/src/external/custom-view.element.ts
new file mode 100644
index 0000000000..0bc3ba8719
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/external/custom-view.element.ts
@@ -0,0 +1,49 @@
+import {LitElement} from "lit";
+import {customElement, property, state} from "lit/decorators.js";
+import {until} from "lit/directives/until.js";
+import {loadCustomView, renderCustomView} from "../utils/load-custom-view.function.js";
+
+@customElement('umb-custom-view')
+export default class UmbCustomViewElement extends LitElement {
+ @property({ attribute: 'custom-view' })
+ customView?: string;
+
+ @property({ attribute: 'args' })
+ args?: any;
+
+ @state()
+ protected component: any = null;
+
+ attributeChangedCallback(name: string, _old: string | null, value: string | null) {
+ super.attributeChangedCallback(name, _old, value);
+ if (name === 'custom-view') {
+ this.#loadView();
+ }
+ }
+
+ async #loadView() {
+ if (!this.customView || !this.customView.endsWith('.js') && !this.customView.endsWith('.html')) {
+ return;
+ }
+
+ const customView = await loadCustomView(this.customView);
+
+ if (this.args) {
+ Object.entries(this.args).forEach(([key, value]) => {
+ (customView as any)[key] = value;
+ });
+ }
+
+ this.component = renderCustomView(customView);
+ }
+
+ render() {
+ return until(this.component);
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-custom-view': UmbCustomViewElement;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/external/icon.registry.ts b/src/Umbraco.Web.UI.Login/src/external/icon.registry.ts
new file mode 100644
index 0000000000..f1eb8af6fb
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/external/icon.registry.ts
@@ -0,0 +1,65 @@
+import { UUIIconRegistry, UUIIconRegistryElement, UUIIconRegistryEssential } from '@umbraco-ui/uui';
+import { Observable, ReplaySubject } from 'rxjs';
+import { customElement } from 'lit/decorators.js';
+
+/**
+ * This is a custom icon registry that will load icons from the Umbraco assets folder.
+ * Optimistically, we will provide the icon, and then try and load it.
+ */
+class UmbIconRegistry extends UUIIconRegistry {
+ protected acceptIcon(iconName: string): boolean {
+ // If the icon name is a variable, we will not provide it.
+ if (iconName.startsWith('{{') && iconName.endsWith('}}')) {
+ return false;
+ }
+
+ // Inform that we will be providing this.
+ const icon = this.provideIcon(iconName);
+
+ this.#getIcons().subscribe((icons) => {
+ if (icons[iconName]) {
+ icon.svg = icons[iconName];
+ } else {
+ // If we can't load the icon, we will not provide it.
+ console.warn(`Icon ${iconName} not found`);
+ }
+ });
+
+ return true;
+ }
+
+ #iconsLoaded = false;
+ #icons = new ReplaySubject>(1);
+ #getIcons(): Observable> {
+ if (!this.#iconsLoaded) {
+ this.#iconsLoaded = true;
+ fetch('backoffice/umbracoapi/icon/geticons')
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error('Could not fetch icons');
+ }
+
+ return response.json();
+ })
+ .then((icons) => {
+ this.#icons.next(icons);
+ this.#icons.complete();
+ });
+ }
+
+ return this.#icons.asObservable();
+ }
+}
+
+@customElement('umb-backoffice-icon-registry')
+export class UmbBackofficeIconRegistryElement extends UUIIconRegistryElement {
+ constructor() {
+ super();
+ new UUIIconRegistryEssential().attach(this);
+ this.registry = new UmbIconRegistry();
+ }
+
+ protected createRenderRoot() {
+ return this;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Login/src/external/localization/localization-context.ts b/src/Umbraco.Web.UI.Login/src/external/localization/localization-context.ts
new file mode 100644
index 0000000000..f557c4facd
--- /dev/null
+++ b/src/Umbraco.Web.UI.Login/src/external/localization/localization-context.ts
@@ -0,0 +1,104 @@
+import { firstValueFrom, ReplaySubject } from 'rxjs';
+
+class UmbLocalizationContext {
+ #init = false;
+ readonly #apiBasePath = 'localizedtext';
+ #innerDictionary = new ReplaySubject