From 566453191dd3f4fb36ed786024848605720024f8 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Thu, 29 Feb 2024 15:32:49 -0600 Subject: [PATCH] initial release --- .editorconfig | 11 + .gitignore | 9 + .prettierrc | 4 + LICENSE | 201 ++ META-INF/keycloak-themes.json | 8 + README.md | 114 + dump.rdb | Bin 0 -> 1020 bytes html/login/error.html | 49 + html/login/login-config-totp.html | 76 + html/login/login-idp-link-confirm.html | 52 + html/login/login-oauth-grant.html | 59 + html/login/login-otp.html | 59 + html/login/login-page-expired.html | 52 + html/login/login-password.html | 75 + .../login-recovery-authn-code-config.html | 84 + .../login-recovery-authn-code-input.html | 59 + html/login/login-reset-password.html | 63 + html/login/login-update-password.html | 91 + html/login/login-update-profile.html | 74 + html/login/login-username.html | 90 + html/login/login-x509-info.html | 65 + html/login/login.html | 109 + html/login/logout-confirm.html | 53 + html/login/register.html | 70 + html/login/select-authenticator.html | 60 + html/login/webauthn-authenticate.html | 70 + html/login/webauthn-error.html | 57 + out/keywind.jar | Bin 0 -> 108867 bytes package-lock.json | 2562 +++++++++++++++++ package.json | 27 + pnpm-lock.yaml | 1261 ++++++++ pom.xml | 71 + postcss.config.js | 6 + preview.png | Bin 0 -> 27257 bytes scripts/build.ts | 25 + src/data/recoveryCodes.ts | 59 + src/data/webAuthnAuthenticate.ts | 147 + src/data/webAuthnRegister.ts | 225 ++ src/global.d.ts | 8 + src/index.css | 33 + src/index.ts | 7 + .../org/keywind/theme/AuthenticationUtil.java | 13 + .../org/keywind/theme/LoginDataModel.java | 265 ++ .../org/keywind/theme/LoginThemeTest.java | 113 + tailwind.config.ts | 37 + .../icons/arrow-top-right-on-square.ftl | 7 + .../login/assets/icons/chevron-down.ftl | 6 + .../keywind/login/assets/icons/eye-slash.ftl | 7 + theme/keywind/login/assets/icons/eye.ftl | 7 + .../login/assets/icons/header-logo.png | Bin 0 -> 16932 bytes .../keywind/login/assets/providers/apple.ftl | 7 + .../login/assets/providers/bitbucket.ftl | 14 + .../login/assets/providers/discord.ftl | 7 + .../login/assets/providers/facebook.ftl | 8 + .../keywind/login/assets/providers/github.ftl | 7 + .../keywind/login/assets/providers/gitlab.ftl | 10 + .../keywind/login/assets/providers/google.ftl | 10 + .../login/assets/providers/instagram.ftl | 35 + .../login/assets/providers/linkedin.ftl | 7 + .../login/assets/providers/microsoft.ftl | 10 + theme/keywind/login/assets/providers/oidc.ftl | 9 + .../login/assets/providers/openshift.ftl | 11 + .../keywind/login/assets/providers/paypal.ftl | 9 + .../login/assets/providers/providers.ftl | 84 + .../keywind/login/assets/providers/slack.ftl | 14 + .../login/assets/providers/stackoverflow.ftl | 8 + .../login/assets/providers/twitter.ftl | 7 + .../keywind/login/components/atoms/alert.ftl | 22 + theme/keywind/login/components/atoms/body.ftl | 5 + .../login/components/atoms/button-group.ftl | 5 + .../keywind/login/components/atoms/button.ftl | 33 + theme/keywind/login/components/atoms/card.ftl | 19 + .../login/components/atoms/checkbox.ftl | 19 + .../login/components/atoms/container.ftl | 5 + theme/keywind/login/components/atoms/form.ftl | 11 + .../login/components/atoms/heading.ftl | 5 + .../keywind/login/components/atoms/input.ftl | 78 + theme/keywind/login/components/atoms/link.ftl | 30 + theme/keywind/login/components/atoms/logo.ftl | 8 + theme/keywind/login/components/atoms/nav.ftl | 5 + .../keywind/login/components/atoms/radio.ftl | 18 + .../molecules/identity-provider.ftl | 81 + .../components/molecules/locale-provider.ftl | 29 + .../login/components/molecules/username.ftl | 15 + theme/keywind/login/document.ftl | 35 + theme/keywind/login/error.ftl | 18 + .../login/features/labels/totp-device.ftl | 5 + theme/keywind/login/features/labels/totp.ftl | 5 + .../login/features/labels/username.ftl | 11 + theme/keywind/login/login-config-totp.ftl | 110 + .../keywind/login/login-idp-link-confirm.ftl | 18 + theme/keywind/login/login-oauth-grant.ftl | 62 + theme/keywind/login/login-otp.ftl | 50 + theme/keywind/login/login-page-expired.ftl | 18 + theme/keywind/login/login-password.ftl | 39 + .../login-recovery-authn-code-config.ftl | 91 + .../login/login-recovery-authn-code-input.ftl | 26 + theme/keywind/login/login-reset-password.ftl | 48 + theme/keywind/login/login-update-password.ftl | 64 + theme/keywind/login/login-update-profile.ftl | 71 + theme/keywind/login/login-username.ftl | 71 + theme/keywind/login/login-x509-info.ftl | 40 + theme/keywind/login/login.ftl | 87 + theme/keywind/login/logout-confirm.ftl | 25 + theme/keywind/login/register.ftl | 88 + theme/keywind/login/resources/header-logo.png | Bin 0 -> 16932 bytes theme/keywind/login/select-authenticator.ftl | 28 + theme/keywind/login/template.ftl | 84 + theme/keywind/login/terms.ftl | 22 + theme/keywind/login/theme.properties | 4 + theme/keywind/login/webauthn-authenticate.ftl | 71 + theme/keywind/login/webauthn-error.ftl | 34 + theme/keywind/login/webauthn-register.ftl | 54 + tsconfig.json | 21 + tsconfig.node.json | 11 + vite.config.ts | 19 + 116 files changed, 8575 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 LICENSE create mode 100644 META-INF/keycloak-themes.json create mode 100644 README.md create mode 100644 dump.rdb create mode 100644 html/login/error.html create mode 100644 html/login/login-config-totp.html create mode 100644 html/login/login-idp-link-confirm.html create mode 100644 html/login/login-oauth-grant.html create mode 100644 html/login/login-otp.html create mode 100644 html/login/login-page-expired.html create mode 100644 html/login/login-password.html create mode 100644 html/login/login-recovery-authn-code-config.html create mode 100644 html/login/login-recovery-authn-code-input.html create mode 100644 html/login/login-reset-password.html create mode 100644 html/login/login-update-password.html create mode 100644 html/login/login-update-profile.html create mode 100644 html/login/login-username.html create mode 100644 html/login/login-x509-info.html create mode 100644 html/login/login.html create mode 100644 html/login/logout-confirm.html create mode 100644 html/login/register.html create mode 100644 html/login/select-authenticator.html create mode 100644 html/login/webauthn-authenticate.html create mode 100644 html/login/webauthn-error.html create mode 100644 out/keywind.jar create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 pom.xml create mode 100644 postcss.config.js create mode 100644 preview.png create mode 100644 scripts/build.ts create mode 100644 src/data/recoveryCodes.ts create mode 100644 src/data/webAuthnAuthenticate.ts create mode 100644 src/data/webAuthnRegister.ts create mode 100644 src/global.d.ts create mode 100644 src/index.css create mode 100644 src/index.ts create mode 100644 src/test/java/org/keywind/theme/AuthenticationUtil.java create mode 100644 src/test/java/org/keywind/theme/LoginDataModel.java create mode 100644 src/test/java/org/keywind/theme/LoginThemeTest.java create mode 100644 tailwind.config.ts create mode 100644 theme/keywind/login/assets/icons/arrow-top-right-on-square.ftl create mode 100644 theme/keywind/login/assets/icons/chevron-down.ftl create mode 100644 theme/keywind/login/assets/icons/eye-slash.ftl create mode 100644 theme/keywind/login/assets/icons/eye.ftl create mode 100644 theme/keywind/login/assets/icons/header-logo.png create mode 100644 theme/keywind/login/assets/providers/apple.ftl create mode 100644 theme/keywind/login/assets/providers/bitbucket.ftl create mode 100644 theme/keywind/login/assets/providers/discord.ftl create mode 100644 theme/keywind/login/assets/providers/facebook.ftl create mode 100644 theme/keywind/login/assets/providers/github.ftl create mode 100644 theme/keywind/login/assets/providers/gitlab.ftl create mode 100644 theme/keywind/login/assets/providers/google.ftl create mode 100644 theme/keywind/login/assets/providers/instagram.ftl create mode 100644 theme/keywind/login/assets/providers/linkedin.ftl create mode 100644 theme/keywind/login/assets/providers/microsoft.ftl create mode 100644 theme/keywind/login/assets/providers/oidc.ftl create mode 100644 theme/keywind/login/assets/providers/openshift.ftl create mode 100644 theme/keywind/login/assets/providers/paypal.ftl create mode 100644 theme/keywind/login/assets/providers/providers.ftl create mode 100644 theme/keywind/login/assets/providers/slack.ftl create mode 100644 theme/keywind/login/assets/providers/stackoverflow.ftl create mode 100644 theme/keywind/login/assets/providers/twitter.ftl create mode 100644 theme/keywind/login/components/atoms/alert.ftl create mode 100644 theme/keywind/login/components/atoms/body.ftl create mode 100644 theme/keywind/login/components/atoms/button-group.ftl create mode 100644 theme/keywind/login/components/atoms/button.ftl create mode 100644 theme/keywind/login/components/atoms/card.ftl create mode 100644 theme/keywind/login/components/atoms/checkbox.ftl create mode 100644 theme/keywind/login/components/atoms/container.ftl create mode 100644 theme/keywind/login/components/atoms/form.ftl create mode 100644 theme/keywind/login/components/atoms/heading.ftl create mode 100644 theme/keywind/login/components/atoms/input.ftl create mode 100644 theme/keywind/login/components/atoms/link.ftl create mode 100644 theme/keywind/login/components/atoms/logo.ftl create mode 100644 theme/keywind/login/components/atoms/nav.ftl create mode 100644 theme/keywind/login/components/atoms/radio.ftl create mode 100644 theme/keywind/login/components/molecules/identity-provider.ftl create mode 100644 theme/keywind/login/components/molecules/locale-provider.ftl create mode 100644 theme/keywind/login/components/molecules/username.ftl create mode 100644 theme/keywind/login/document.ftl create mode 100644 theme/keywind/login/error.ftl create mode 100644 theme/keywind/login/features/labels/totp-device.ftl create mode 100644 theme/keywind/login/features/labels/totp.ftl create mode 100644 theme/keywind/login/features/labels/username.ftl create mode 100644 theme/keywind/login/login-config-totp.ftl create mode 100644 theme/keywind/login/login-idp-link-confirm.ftl create mode 100644 theme/keywind/login/login-oauth-grant.ftl create mode 100644 theme/keywind/login/login-otp.ftl create mode 100644 theme/keywind/login/login-page-expired.ftl create mode 100644 theme/keywind/login/login-password.ftl create mode 100644 theme/keywind/login/login-recovery-authn-code-config.ftl create mode 100644 theme/keywind/login/login-recovery-authn-code-input.ftl create mode 100644 theme/keywind/login/login-reset-password.ftl create mode 100644 theme/keywind/login/login-update-password.ftl create mode 100644 theme/keywind/login/login-update-profile.ftl create mode 100644 theme/keywind/login/login-username.ftl create mode 100644 theme/keywind/login/login-x509-info.ftl create mode 100644 theme/keywind/login/login.ftl create mode 100644 theme/keywind/login/logout-confirm.ftl create mode 100644 theme/keywind/login/register.ftl create mode 100644 theme/keywind/login/resources/header-logo.png create mode 100644 theme/keywind/login/select-authenticator.ftl create mode 100644 theme/keywind/login/template.ftl create mode 100644 theme/keywind/login/terms.ftl create mode 100644 theme/keywind/login/theme.properties create mode 100644 theme/keywind/login/webauthn-authenticate.ftl create mode 100644 theme/keywind/login/webauthn-error.ftl create mode 100644 theme/keywind/login/webauthn-register.ftl create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7c1e13a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..22aa52b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules/ + +# misc +.DS_Store + +dist \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5ac85e2 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "printWidth": 100, + "singleQuote": true +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/META-INF/keycloak-themes.json b/META-INF/keycloak-themes.json new file mode 100644 index 0000000..2352cc0 --- /dev/null +++ b/META-INF/keycloak-themes.json @@ -0,0 +1,8 @@ +{ + "themes": [ + { + "name": "keywind", + "types": ["login"] + } + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..03f842c --- /dev/null +++ b/README.md @@ -0,0 +1,114 @@ +# :wind_face: Keywind + +Keywind is a component-based Keycloak Login Theme built with [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss) and [Alpine.js](https://github.com/alpinejs/alpine). + +![Preview](./preview.png) + +### Styled Pages + +- Error +- Login +- Login Config TOTP +- Login IDP Link Confirm +- Login OAuth Grant +- Login OTP +- Login Page Expired +- Login Password +- Login Recovery Authn Code Config +- Login Recovery Authn Code Input +- Login Reset Password +- Login Update Password +- Login Update Profile +- Login Username +- Login X.509 Info +- Logout Confirm +- Register +- Select Authenticator +- Terms and Conditions +- WebAuthn Authenticate +- WebAuthn Error +- WebAuthn Register + +### Identity Provider Icons + +- Apple +- Bitbucket +- Discord +- Facebook +- GitHub +- GitLab +- Google +- Instagram +- LinkedIn +- Microsoft +- OpenID +- Red Hat OpenShift +- PayPal +- Slack +- Stack Overflow +- Twitter + +## Installation + +Keywind has been designed with component-based architecture from the start, and **you can customize as little or as much Keywind as you need**: + +1. [Deploy Keywind Login Theme](https://www.keycloak.org/docs/latest/server_development/#deploying-themes) +2. [Create your own Login Theme](https://www.keycloak.org/docs/latest/server_development/#creating-a-theme) +3. Specify parent theme in [theme properties](https://www.keycloak.org/docs/latest/server_development/#theme-properties): + +``` +parent=keywind +``` + +4. Brand and customize components with [FreeMarker](https://freemarker.apache.org/docs/dgui_quickstart_template.html) + +## Customization + +### Theme + +When you do need to customize a palette, you can configure your colors under the `colors` key in the `theme` section of Tailwind config file: + +`tailwind.config.js` + +```js +module.exports = { + theme: { + extend: { + colors: { + primary: colors.red, + }, + }, + }, +}; +``` + +Read more about Tailwind CSS configuration in the [documentation](https://tailwindcss.com/docs/configuration). + +### Components + +You can update Keywind components in your own child theme. For example, create a copy of the `body` component and change the background: + +`theme/mytheme/login/components/atoms/body.ftl` + +``` +<#macro kw> + + <#nested> + + +``` + +## Build + +When you're ready to deploy your own theme, run the build command to generate a static production build. + +```bash +pnpm install +pnpm build +``` + +To deploy a theme as an archive, create a JAR archive with the theme resources. + +```bash +pnpm build:jar +``` diff --git a/dump.rdb b/dump.rdb new file mode 100644 index 0000000000000000000000000000000000000000..9562b9f31961304c935e38a244cc27186a3bd349 GIT binary patch literal 1020 zcmaLW&u<$=6bJC}dL5@uDvN?5B7=Cl22s%3+I6yNFanM3I+CUELry9oMO8iCeXgfn z@0yueCng}0KLCkxL*!si2#z3*pim?vP8>LJ0TCg@sZvk9nDS%WG_(SV>(k6Te7~R9 zZk}&#*tX+LPYLw7ER9fP&Xp_W+1xwdWDwhd3wrK|*j zBMf6&&>X9BL<-u=s9-4_^|*rN)QY=TIepPGeUzTyL&c+zUd(LvxddMenbL; zZSEtCnBb_!5cPmhzDuJl!%_MgJgRv?44Wyaf2ikxg+8c0LL1?>)|AS4y7MsfQ)~$D zX*;mgc_#z%b?7PJv#JjwiU!a#W>UCg6p4g`$!l~vadj7%CpvG>btQ%h5kwrqSG%N4 zf7H}?SbLLHj6ynyJhu0%Zf@cZt9`)gnpt%X3dHaYk&^BG7m|TvJP%~fGCd~yYeBSa zR*e-PvzFNv(Nz@d#$GD);9c6*+sy{lI}2GTy3WeE)m4xL;RflNPo(;2TD5OA%M^yb zpC+ySv#_Wu5#w7A!l*n5<4Wz|1V-fq2AwAk{6CJzPjD + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

We are sorry...

+
+
+ +
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-config-totp.html b/html/login/login-config-totp.html new file mode 100644 index 0000000..f348b1f --- /dev/null +++ b/html/login/login-config-totp.html @@ -0,0 +1,76 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Mobile Authenticator Setup

+
+
+ +
    +
  1. +

    Install one of the following applications on your mobile:

    +
      +
    • FreeOTP
    • +
  2. +
  3. +

    Open the application and scan the barcode:

    Figure: Barcode Unable to scan?
  4. +
  5. Enter the one-time code provided by the application and click Submit to finish the setup.
  6. +
  7. Provide a Device Name to help you manage your OTP devices.
  8. +
+
+ +
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-idp-link-confirm.html b/html/login/login-idp-link-confirm.html new file mode 100644 index 0000000..149daf8 --- /dev/null +++ b/html/login/login-idp-link-confirm.html @@ -0,0 +1,52 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Account already exists

+
+
+ +
+ +
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-oauth-grant.html b/html/login/login-oauth-grant.html new file mode 100644 index 0000000..493fe85 --- /dev/null +++ b/html/login/login-oauth-grant.html @@ -0,0 +1,59 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

+

Grant Access to null

+
+
+ +

Do you grant these access privileges?

+
    +
+
+ +
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-otp.html b/html/login/login-otp.html new file mode 100644 index 0000000..8476be5 --- /dev/null +++ b/html/login/login-otp.html @@ -0,0 +1,59 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Sign In

+
+
+ +
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-page-expired.html b/html/login/login-page-expired.html new file mode 100644 index 0000000..64db4a4 --- /dev/null +++ b/html/login/login-page-expired.html @@ -0,0 +1,52 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Page has expired

+
+
+ + +
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-password.html b/html/login/login-password.html new file mode 100644 index 0000000..cdca5ef --- /dev/null +++ b/html/login/login-password.html @@ -0,0 +1,75 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Sign In

+
+
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-recovery-authn-code-config.html b/html/login/login-recovery-authn-code-config.html new file mode 100644 index 0000000..5a7a96a --- /dev/null +++ b/html/login/login-recovery-authn-code-config.html @@ -0,0 +1,84 @@ + + + Sign in to + + + + + + + + +
+
+
+
+ Keywind +
+

Recovery Authentication Codes

+
+
+ +
+ +
    +
  • 0000-0000-0000
  • +
  • 1111-1111-1111
  • +
+
+ +
+
+ +
+ +
+
+ +
+
+
+
+ +
+
+
+
+
+ + +
+
+
+ + + \ No newline at end of file diff --git a/html/login/login-recovery-authn-code-input.html b/html/login/login-recovery-authn-code-input.html new file mode 100644 index 0000000..0f10d6f --- /dev/null +++ b/html/login/login-recovery-authn-code-input.html @@ -0,0 +1,59 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Login with a recovery authentication code

+
+
+ +
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-reset-password.html b/html/login/login-reset-password.html new file mode 100644 index 0000000..a56248c --- /dev/null +++ b/html/login/login-reset-password.html @@ -0,0 +1,63 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Forgot Your Password?

+
+
+ +
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+ Enter your username and we will send you instructions on how to create a new password. +
+
+
+ « Back to Login +
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-update-password.html b/html/login/login-update-password.html new file mode 100644 index 0000000..c223fa8 --- /dev/null +++ b/html/login/login-update-password.html @@ -0,0 +1,91 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Update password

+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-update-profile.html b/html/login/login-update-profile.html new file mode 100644 index 0000000..971a3ff --- /dev/null +++ b/html/login/login-update-profile.html @@ -0,0 +1,74 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Update Account Information

+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-username.html b/html/login/login-username.html new file mode 100644 index 0000000..d5db05e --- /dev/null +++ b/html/login/login-username.html @@ -0,0 +1,90 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Sign in to your account

+
+
+ +
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+ Or sign in with +
+ +
+
+
+ New user? Register +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login-x509-info.html b/html/login/login-x509-info.html new file mode 100644 index 0000000..5d26f88 --- /dev/null +++ b/html/login/login-x509-info.html @@ -0,0 +1,65 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Sign In

+
+
+ +
+
+ X509 client certificate: +
+
+ CN=User, C=US, O=Keywind +
+
+
+ You will be logged in as: Username +
+
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/login.html b/html/login/login.html new file mode 100644 index 0000000..d24c358 --- /dev/null +++ b/html/login/login.html @@ -0,0 +1,109 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Sign in to your account

+
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+
+
+ +
Forgot Password? +
+
+ +
+
+
+ +
+
+ Or sign in with +
+ +
+
+
+ New user? Register +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/logout-confirm.html b/html/login/logout-confirm.html new file mode 100644 index 0000000..e13b12d --- /dev/null +++ b/html/login/logout-confirm.html @@ -0,0 +1,53 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Logging out

+
+
+ +

Do you want to log out?

+
+ +
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/register.html b/html/login/register.html new file mode 100644 index 0000000..b1f3691 --- /dev/null +++ b/html/login/register.html @@ -0,0 +1,70 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Register

+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+ « Back to Login +
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/select-authenticator.html b/html/login/select-authenticator.html new file mode 100644 index 0000000..248bea3 --- /dev/null +++ b/html/login/select-authenticator.html @@ -0,0 +1,60 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Select login method

+
+
+ +
+
+ +
+ +
+ Use your security key to sign in. +
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/html/login/webauthn-authenticate.html b/html/login/webauthn-authenticate.html new file mode 100644 index 0000000..dbc3c3e --- /dev/null +++ b/html/login/webauthn-authenticate.html @@ -0,0 +1,70 @@ + + + Sign in to + + + + + + + + +
+
+
+
+ Keywind +
+

Security Key login

+
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + + \ No newline at end of file diff --git a/html/login/webauthn-error.html b/html/login/webauthn-error.html new file mode 100644 index 0000000..24e893d --- /dev/null +++ b/html/login/webauthn-error.html @@ -0,0 +1,57 @@ + + + Sign in to + + + + + + + +
+
+
+
+ Keywind +
+

Security Key Error

+
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/out/keywind.jar b/out/keywind.jar new file mode 100644 index 0000000000000000000000000000000000000000..761ed4675d6ab50c6cc4aa11756cf53546778551 GIT binary patch literal 108867 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 literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3b23107 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2562 @@ +{ + "name": "keywind", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "keywind", + "dependencies": { + "alpinejs": "^3.13.0", + "rfc4648": "^1.5.2" + }, + "devDependencies": { + "@tailwindcss/forms": "^0.5.6", + "@types/alpinejs": "^3.13.2", + "@types/archiver": "^5.3.3", + "@types/node": "^20.6.5", + "archiver": "^6.0.1", + "autoprefixer": "^10.4.16", + "postcss": "^8.4.30", + "tailwindcss": "^3.3.3", + "typescript": "^5.2.2", + "vite": "^4.4.9", + "vite-node": "^0.34.5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", + "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", + "dev": true, + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + } + }, + "node_modules/@types/alpinejs": { + "version": "3.13.6", + "resolved": "https://registry.npmjs.org/@types/alpinejs/-/alpinejs-3.13.6.tgz", + "integrity": "sha512-BMi1/2uQz7mp30VFn69SzjN7YwQ0QzE4Hn3RMBt4iMpQeasdbMiImv1f5yvK1bYmvjIyG/YFg+CgPxbjIXZk0g==", + "dev": true + }, + "node_modules/@types/archiver": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.4.tgz", + "integrity": "sha512-Lj7fLBIMwYFgViVVZHEdExZC3lVYsl+QL0VmdNdIzGZH544jHveYWij6qdnBgJQDnR7pMKliN9z2cPZFEbhyPw==", + "dev": true, + "dependencies": { + "@types/readdir-glob": "*" + } + }, + "node_modules/@types/node": { + "version": "20.11.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.18.tgz", + "integrity": "sha512-ABT5VWnnYneSBcNWYSCuR05M826RoMyMSGiFivXGx6ZUIsXb9vn4643IEwkg2zbEOSgAiSogtapN2fgc4mAPlw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/readdir-glob": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.5.tgz", + "integrity": "sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", + "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==", + "dependencies": { + "@vue/shared": "3.1.5" + } + }, + "node_modules/@vue/shared": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", + "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/alpinejs": { + "version": "3.13.5", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.5.tgz", + "integrity": "sha512-1d2XeNGN+Zn7j4mUAKXtAgdc4/rLeadyTMWeJGXF5DzwawPBxwTiBhFFm6w/Ei8eJxUZeyNWWSD9zknfdz1kEw==", + "dependencies": { + "@vue/reactivity": "~3.1.1" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/archiver": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-6.0.1.tgz", + "integrity": "sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==", + "dev": true, + "dependencies": { + "archiver-utils": "^4.0.1", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^5.0.1" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/archiver-utils": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-4.0.1.tgz", + "integrity": "sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==", + "dev": true, + "dependencies": { + "glob": "^8.0.0", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.17", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", + "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.22.2", + "caniuse-lite": "^1.0.30001578", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bare-events": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.0.tgz", + "integrity": "sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==", + "dev": true, + "optional": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.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==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001587", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz", + "integrity": "sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "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" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/compress-commons": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-5.0.1.tgz", + "integrity": "sha512-MPh//1cERdLtqwO3pOFLeXtpuai0Y2WCd5AhtKxznqM7WtaMYaOEMSgn45d9D10sIHSfIKE603HlOp8OPGrvag==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^5.0.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-5.0.0.tgz", + "integrity": "sha512-B0EPa1UK+qnpBZpG+7FgPCu0J2ETLpXq09o9BkLkEAhdB6Z61Qo4pJ3JYu0c+Qi+/SAL7QThqnzS06pmSSyZaw==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.670", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.670.tgz", + "integrity": "sha512-hcijYOWjOtjKrKPtNA6tuLlA/bTLO3heFG8pQA6mLpq7dRydSWicXova5lyxDzp1iVJaYhK7J2OQlGE52KYn7A==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true, + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mlly": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.5.0.tgz", + "integrity": "sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.0.3", + "ufo": "^1.3.2" + } + }, + "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==", + "dev": true + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "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-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": 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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "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.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.0.tgz", + "integrity": "sha512-p3cz0JV5vw/XeouBU3Ldnp+ZkBjE+n8ydJ4mcwBrOiXXPqNlrzGBqWs9X4MWF7f+iKUBu794Y8Hh8yawiJbCjw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfc4648": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/rfc4648/-/rfc4648-1.5.3.tgz", + "integrity": "sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==" + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/streamx": { + "version": "2.15.8", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.8.tgz", + "integrity": "sha512-6pwMeMY/SuISiRsuS8TeIrAzyFbG5gGPHFQsYjUr/pbBadaL1PCWmzKw+CHZSwainfvcF6Si6cVLq4XTEwswFQ==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "dev": true + }, + "node_modules/string-width-cjs/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==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", + "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vite": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "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/vite-node": { + "version": "0.34.7", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.7.tgz", + "integrity": "sha512-0Yzb96QzHmqIKIs/x2q/sqG750V/EF6yDkS2p1WjJc1W2bgRSuQjf5vB9HY8h2nVb5j4pO5paS5Npcv3s69YUg==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.4.0", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "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==", + "dev": true, + "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/wrap-ansi-cjs/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-5.0.1.tgz", + "integrity": "sha512-UfZ0oa0C8LI58wJ+moL46BDIMgCQbnsb+2PoiJYtonhBsMh2bq1eRBVkvjfVsqbEHd9/EgKPUuL9saSSsec8OA==", + "dev": true, + "dependencies": { + "archiver-utils": "^4.0.1", + "compress-commons": "^5.0.1", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 12.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7f84d04 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://json.schemastore.org/package", + "name": "keywind", + "scripts": { + "build": "tsc && vite build", + "build:jar": "vite-node scripts/build", + "dev": "vite dev --host", + "test": "mvn test" + }, + "dependencies": { + "alpinejs": "^3.13.0", + "rfc4648": "^1.5.2" + }, + "devDependencies": { + "@tailwindcss/forms": "^0.5.6", + "@types/alpinejs": "^3.13.2", + "@types/archiver": "^5.3.3", + "@types/node": "^20.6.5", + "archiver": "^6.0.1", + "autoprefixer": "^10.4.16", + "postcss": "^8.4.30", + "tailwindcss": "^3.3.3", + "typescript": "^5.2.2", + "vite": "^4.4.9", + "vite-node": "^0.34.5" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..3c60020 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1261 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + alpinejs: + specifier: ^3.13.0 + version: 3.13.0 + rfc4648: + specifier: ^1.5.2 + version: 1.5.2 + +devDependencies: + '@tailwindcss/forms': + specifier: ^0.5.6 + version: 0.5.6(tailwindcss@3.3.3) + '@types/alpinejs': + specifier: ^3.13.2 + version: 3.13.2 + '@types/archiver': + specifier: ^5.3.3 + version: 5.3.3 + '@types/node': + specifier: ^20.6.5 + version: 20.6.5 + archiver: + specifier: ^6.0.1 + version: 6.0.1 + autoprefixer: + specifier: ^10.4.16 + version: 10.4.16(postcss@8.4.30) + postcss: + specifier: ^8.4.30 + version: 8.4.30 + tailwindcss: + specifier: ^3.3.3 + version: 3.3.3 + typescript: + specifier: ^5.2.2 + version: 5.2.2 + vite: + specifier: ^4.4.9 + version: 4.4.9(@types/node@20.6.5) + vite-node: + specifier: ^0.34.5 + version: 0.34.5(@types/node@20.6.5) + +packages: + + /@alloc/quick-lru@5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.19 + dev: true + + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@tailwindcss/forms@0.5.6(tailwindcss@3.3.3): + resolution: {integrity: sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==} + peerDependencies: + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' + dependencies: + mini-svg-data-uri: 1.4.4 + tailwindcss: 3.3.3 + dev: true + + /@types/alpinejs@3.13.2: + resolution: {integrity: sha512-kRGGjngGMCw8H4BIDbaDLwuGNIsrzdvt54kKqLe6O8ZLTNW5swEMr6j2ByH/vUo46ajqf2Qbxh6fcxPDrfEU+Q==} + dev: true + + /@types/archiver@5.3.3: + resolution: {integrity: sha512-0ABdVcXL6jOwNGY+hjWPqrxUvKelBEwNLcuv/SV2vZ4YCH8w9NttFCt+/QqI5zgMX+iX/XqVy89/r7EmLJmMpQ==} + dependencies: + '@types/readdir-glob': 1.1.1 + dev: true + + /@types/node@20.6.5: + resolution: {integrity: sha512-2qGq5LAOTh9izcc0+F+dToFigBWiK1phKPt7rNhOqJSr35y8rlIBjDwGtFSgAI6MGIhjwOVNSQZVdJsZJ2uR1w==} + dev: true + + /@types/readdir-glob@1.1.1: + resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==} + dependencies: + '@types/node': 20.6.5 + dev: true + + /@vue/reactivity@3.1.5: + resolution: {integrity: sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==} + dependencies: + '@vue/shared': 3.1.5 + dev: false + + /@vue/shared@3.1.5: + resolution: {integrity: sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==} + dev: false + + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /alpinejs@3.13.0: + resolution: {integrity: sha512-7FYR1Yz3evIjlJD1mZ3SYWSw+jlOmQGeQ1QiSufSQ6J84XMQFkzxm6OobiZ928SfqhGdoIp2SsABNsS4rXMMJw==} + dependencies: + '@vue/reactivity': 3.1.5 + dev: false + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /archiver-utils@4.0.1: + resolution: {integrity: sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==} + engines: {node: '>= 12.0.0'} + dependencies: + glob: 8.1.0 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + dev: true + + /archiver@6.0.1: + resolution: {integrity: sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==} + engines: {node: '>= 12.0.0'} + dependencies: + archiver-utils: 4.0.1 + async: 3.2.4 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 3.1.6 + zip-stream: 5.0.1 + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /async@3.2.4: + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + dev: true + + /autoprefixer@10.4.16(postcss@8.4.30): + resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.21.11 + caniuse-lite: 1.0.30001539 + fraction.js: 4.3.6 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.30 + postcss-value-parser: 4.2.0 + dev: true + + /b4a@1.6.4: + resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browserslist@4.21.11: + resolution: {integrity: sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001539 + electron-to-chromium: 1.4.528 + node-releases: 2.0.13 + update-browserslist-db: 1.0.13(browserslist@4.21.11) + dev: true + + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + + /cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: true + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: true + + /caniuse-lite@1.0.30001539: + resolution: {integrity: sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA==} + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /compress-commons@5.0.1: + resolution: {integrity: sha512-MPh//1cERdLtqwO3pOFLeXtpuai0Y2WCd5AhtKxznqM7WtaMYaOEMSgn45d9D10sIHSfIKE603HlOp8OPGrvag==} + engines: {node: '>= 12.0.0'} + dependencies: + crc-32: 1.2.2 + crc32-stream: 5.0.0 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: true + + /crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + dev: true + + /crc32-stream@5.0.0: + resolution: {integrity: sha512-B0EPa1UK+qnpBZpG+7FgPCu0J2ETLpXq09o9BkLkEAhdB6Z61Qo4pJ3JYu0c+Qi+/SAL7QThqnzS06pmSSyZaw==} + engines: {node: '>= 12.0.0'} + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + dev: true + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: true + + /electron-to-chromium@1.4.528: + resolution: {integrity: sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==} + dev: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: true + + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /fraction.js@4.3.6: + resolution: {integrity: sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==} + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + dependencies: + has: 1.0.3 + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: true + + /jiti@1.20.0: + resolution: {integrity: sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==} + hasBin: true + dev: true + + /jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + + /lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + dependencies: + readable-stream: 2.3.8 + dev: true + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mini-svg-data-uri@1.4.4: + resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + hasBin: true + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /mlly@1.4.2: + resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} + dependencies: + acorn: 8.10.0 + pathe: 1.1.1 + pkg-types: 1.0.3 + ufo: 1.3.0 + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /pathe@1.1.1: + resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + dev: true + + /pkg-types@1.0.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.4.2 + pathe: 1.1.1 + dev: true + + /postcss-import@15.1.0(postcss@8.4.30): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.30 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.6 + dev: true + + /postcss-js@4.0.1(postcss@8.4.30): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.30 + dev: true + + /postcss-load-config@4.0.1(postcss@8.4.30): + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + postcss: 8.4.30 + yaml: 2.3.2 + dev: true + + /postcss-nested@6.0.1(postcss@8.4.30): + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.30 + postcss-selector-parser: 6.0.13 + dev: true + + /postcss-selector-parser@6.0.13: + resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + + /postcss@8.4.30: + resolution: {integrity: sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + dev: true + + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + dev: true + + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true + + /readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + dependencies: + minimatch: 5.1.6 + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /resolve@1.22.6: + resolution: {integrity: sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==} + hasBin: true + dependencies: + is-core-module: 2.13.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rfc4648@1.5.2: + resolution: {integrity: sha512-tLOizhR6YGovrEBLatX1sdcuhoSCXddw3mqNVAcKxGJ+J0hFeJ+SjeWCv5UPA/WU3YzWPPuCVYgXBKZUPGpKtg==} + dev: false + + /rollup@3.29.3: + resolution: {integrity: sha512-T7du6Hum8jOkSWetjRgbwpM6Sy0nECYrYRSmZjayFcOddtKJWU4d17AC3HNUk7HRuqy4p+G7aEZclSHytqUmEg==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /streamx@2.15.1: + resolution: {integrity: sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==} + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + dev: true + + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /sucrase@3.34.0: + resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} + engines: {node: '>=8'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 7.1.6 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /tailwindcss@3.3.3: + resolution: {integrity: sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.5.3 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.1 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.20.0 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.30 + postcss-import: 15.1.0(postcss@8.4.30) + postcss-js: 4.0.1(postcss@8.4.30) + postcss-load-config: 4.0.1(postcss@8.4.30) + postcss-nested: 6.0.1(postcss@8.4.30) + postcss-selector-parser: 6.0.13 + resolve: 1.22.6 + sucrase: 3.34.0 + transitivePeerDependencies: + - ts-node + dev: true + + /tar-stream@3.1.6: + resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} + dependencies: + b4a: 1.6.4 + fast-fifo: 1.3.2 + streamx: 2.15.1 + dev: true + + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /ufo@1.3.0: + resolution: {integrity: sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==} + dev: true + + /update-browserslist-db@1.0.13(browserslist@4.21.11): + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.11 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /vite-node@0.34.5(@types/node@20.6.5): + resolution: {integrity: sha512-RNZ+DwbCvDoI5CbCSQSyRyzDTfFvFauvMs6Yq4ObJROKlIKuat1KgSX/Ako5rlDMfVCyMcpMRMTkJBxd6z8YRA==} + engines: {node: '>=v14.18.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.4.2 + pathe: 1.1.1 + picocolors: 1.0.0 + vite: 4.4.9(@types/node@20.6.5) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vite@4.4.9(@types/node@20.6.5): + resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + 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 + dependencies: + '@types/node': 20.6.5 + esbuild: 0.18.20 + postcss: 8.4.30 + rollup: 3.29.3 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /yaml@2.3.2: + resolution: {integrity: sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==} + engines: {node: '>= 14'} + dev: true + + /zip-stream@5.0.1: + resolution: {integrity: sha512-UfZ0oa0C8LI58wJ+moL46BDIMgCQbnsb+2PoiJYtonhBsMh2bq1eRBVkvjfVsqbEHd9/EgKPUuL9saSSsec8OA==} + engines: {node: '>= 12.0.0'} + dependencies: + archiver-utils: 4.0.1 + compress-commons: 5.0.1 + readable-stream: 3.6.2 + dev: true diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8d36684 --- /dev/null +++ b/pom.xml @@ -0,0 +1,71 @@ + + + + 4.0.0 + + org.keywind.theme + keywind + 1.0-SNAPSHOT + + keywind + https://keywind.org + + + UTF-8 + 20 + 20 + + + + + org.freemarker + freemarker + 2.3.32 + + + org.jsoup + jsoup + 1.16.1 + + + org.junit.jupiter + junit-jupiter-engine + 5.10.0 + test + + + org.keycloak + keycloak-server-spi-private + 22.0.1 + + + org.keycloak + keycloak-services + 22.0.1 + + + org.keycloak + keycloak-themes + 22.0.1 + + + + + + + maven-clean-plugin + 3.3.1 + + + auto-clean + test + + clean + + + + + + + diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..12a703d --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/preview.png b/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..981558ad712ed5e3abf5b486442e710eb0090bd2 GIT binary patch literal 27257 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 literal 0 HcmV?d00001 diff --git a/scripts/build.ts b/scripts/build.ts new file mode 100644 index 0000000..ecf4b68 --- /dev/null +++ b/scripts/build.ts @@ -0,0 +1,25 @@ +import archiver from 'archiver'; +import { createWriteStream, existsSync, mkdirSync } from 'fs'; + +import { name } from '../package.json'; + +const dir = 'out'; +const file = `${name}.jar`; +const path = `${dir}/${file}`; + +!existsSync(dir) && mkdirSync(dir); + +const output = createWriteStream(`${__dirname}/../${path}`); + +const archive = archiver('zip'); + +archive.on('error', (error) => { + throw error; +}); + +archive.pipe(output); + +archive.directory('META-INF', 'META-INF'); +archive.directory('theme', 'theme'); + +archive.finalize(); diff --git a/src/data/recoveryCodes.ts b/src/data/recoveryCodes.ts new file mode 100644 index 0000000..b329381 --- /dev/null +++ b/src/data/recoveryCodes.ts @@ -0,0 +1,59 @@ +import Alpine from 'alpinejs'; + +type DataType = { + $refs: RefsType; + $store: StoreType; +}; + +type RefsType = { + codeList: HTMLUListElement; +}; + +type StoreType = { + recoveryCodes: { + downloadFileDate: string; + downloadFileDescription: string; + downloadFileHeader: string; + downloadFileName: string; + }; +}; + +document.addEventListener('alpine:init', () => { + Alpine.data('recoveryCodes', function (this: DataType) { + const { codeList } = this.$refs; + const { downloadFileDate, downloadFileDescription, downloadFileHeader, downloadFileName } = + this.$store.recoveryCodes; + + const date = new Date().toLocaleString(navigator.language); + + const codeElements = codeList.getElementsByTagName('li'); + const codes = Array.from(codeElements) + .map((codeElement) => codeElement.innerText) + .join('\n'); + + return { + copy: () => navigator.clipboard.writeText(codes), + download: () => { + const element = document.createElement('a'); + const text = `${downloadFileHeader}\n\n${codes}\n\n${downloadFileDescription}\n\n${downloadFileDate} ${date}`; + + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', `${downloadFileName}.txt`); + element.click(); + }, + print: () => { + const codeListHTML = codeList.innerHTML; + const styles = 'div { font-family: monospace; list-style-type: none }'; + const content = `${downloadFileName}

${downloadFileHeader}

${codeListHTML}

${downloadFileDescription}

${downloadFileDate} ${date}

`; + + const printWindow = window.open(); + + if (printWindow) { + printWindow.document.write(content); + printWindow.print(); + printWindow.close(); + } + }, + }; + }); +}); diff --git a/src/data/webAuthnAuthenticate.ts b/src/data/webAuthnAuthenticate.ts new file mode 100644 index 0000000..8aab5bb --- /dev/null +++ b/src/data/webAuthnAuthenticate.ts @@ -0,0 +1,147 @@ +import Alpine from 'alpinejs'; +import { base64url } from 'rfc4648'; + +type DataType = { + $refs: RefsType; + $store: StoreType; +}; + +type RefsType = { + authenticatorDataInput: HTMLInputElement; + authnSelectForm?: HTMLFormElement; + clientDataJSONInput: HTMLInputElement; + credentialIdInput: HTMLInputElement; + errorInput: HTMLInputElement; + signatureInput: HTMLInputElement; + userHandleInput: HTMLInputElement; + webAuthnForm: HTMLFormElement; +}; + +type StoreType = { + webAuthnAuthenticate: { + challenge: string; + createTimeout: string; + isUserIdentified: string; + rpId: string; + unsupportedBrowserText: string; + userVerification: UserVerificationRequirement | 'not specified'; + }; +}; + +document.addEventListener('alpine:init', () => { + Alpine.data('webAuthnAuthenticate', function (this: DataType) { + const { + authenticatorDataInput, + authnSelectForm, + clientDataJSONInput, + credentialIdInput, + errorInput, + signatureInput, + userHandleInput, + webAuthnForm, + } = this.$refs; + const { + challenge, + createTimeout, + isUserIdentified, + rpId, + unsupportedBrowserText, + userVerification, + } = this.$store.webAuthnAuthenticate; + + const doAuthenticate = (allowCredentials: PublicKeyCredentialDescriptor[]) => { + if (!window.PublicKeyCredential) { + errorInput.value = unsupportedBrowserText; + webAuthnForm.submit(); + + return; + } + + const publicKey: PublicKeyCredentialRequestOptions = { + challenge: base64url.parse(challenge, { loose: true }), + rpId: rpId, + }; + + if (allowCredentials.length) { + publicKey.allowCredentials = allowCredentials; + } + + if (parseInt(createTimeout) !== 0) publicKey.timeout = parseInt(createTimeout) * 1000; + + if (userVerification !== 'not specified') publicKey.userVerification = userVerification; + + navigator.credentials + .get({ publicKey }) + .then((result) => { + if ( + result instanceof PublicKeyCredential && + result.response instanceof AuthenticatorAssertionResponse + ) { + window.result = result; + + authenticatorDataInput.value = base64url.stringify( + new Uint8Array(result.response.authenticatorData), + { pad: false } + ); + + clientDataJSONInput.value = base64url.stringify( + new Uint8Array(result.response.clientDataJSON), + { pad: false } + ); + + signatureInput.value = base64url.stringify(new Uint8Array(result.response.signature), { + pad: false, + }); + + credentialIdInput.value = result.id; + + if (result.response.userHandle) { + userHandleInput.value = base64url.stringify( + new Uint8Array(result.response.userHandle), + { pad: false } + ); + } + + webAuthnForm.submit(); + } + }) + .catch((error) => { + errorInput.value = error; + webAuthnForm.submit(); + }); + }; + + const checkAllowCredentials = () => { + const allowCredentials: PublicKeyCredentialDescriptor[] = []; + + if (authnSelectForm) { + const authnSelectFormElements = Array.from(authnSelectForm.elements); + + if (authnSelectFormElements.length) { + authnSelectFormElements.forEach((element) => { + if (element instanceof HTMLInputElement) { + allowCredentials.push({ + id: base64url.parse(element.value, { loose: true }), + type: 'public-key', + }); + } + }); + } + } + + doAuthenticate(allowCredentials); + }; + + return { + webAuthnAuthenticate: () => { + if (!isUserIdentified) { + doAuthenticate([]); + + return; + } + + checkAllowCredentials(); + }, + }; + }); +}); diff --git a/src/data/webAuthnRegister.ts b/src/data/webAuthnRegister.ts new file mode 100644 index 0000000..23744df --- /dev/null +++ b/src/data/webAuthnRegister.ts @@ -0,0 +1,225 @@ +import Alpine from 'alpinejs'; +import { base64url } from 'rfc4648'; + +type DataType = { + $refs: RefsType; + $store: StoreType; +}; + +type RefsType = { + attestationObjectInput: HTMLInputElement; + authenticatorLabelInput: HTMLInputElement; + clientDataJSONInput: HTMLInputElement; + errorInput: HTMLInputElement; + publicKeyCredentialIdInput: HTMLInputElement; + registerForm: HTMLFormElement; + transportsInput: HTMLInputElement; +}; + +type StoreType = { + webAuthnRegister: { + attestationConveyancePreference: AttestationConveyancePreference | 'not specified'; + authenticatorAttachment: AuthenticatorAttachment | 'not specified'; + challenge: string; + createTimeout: string; + excludeCredentialIds: string; + requireResidentKey: string; + rpEntityName: string; + rpId: string; + signatureAlgorithms: string; + unsupportedBrowserText: string; + userId: string; + userVerificationRequirement: UserVerificationRequirement | 'not specified'; + username: string; + }; +}; + +document.addEventListener('alpine:init', () => { + Alpine.data('webAuthnRegister', function (this: DataType) { + const { + attestationObjectInput, + authenticatorLabelInput, + clientDataJSONInput, + errorInput, + publicKeyCredentialIdInput, + registerForm, + transportsInput, + } = this.$refs; + const { + attestationConveyancePreference, + authenticatorAttachment, + challenge, + createTimeout, + excludeCredentialIds, + requireResidentKey, + rpEntityName, + rpId, + signatureAlgorithms, + unsupportedBrowserText, + userId, + userVerificationRequirement, + username, + } = this.$store.webAuthnRegister; + + const getPubKeyCredParams = (signatureAlgorithms: string) => { + const pubKeyCredParams: PublicKeyCredentialParameters[] = []; + + if (signatureAlgorithms === '') { + pubKeyCredParams.push({ alg: -7, type: 'public-key' }); + + return pubKeyCredParams; + } + + const signatureAlgorithmsList = signatureAlgorithms.split(','); + + signatureAlgorithmsList.forEach((value) => { + pubKeyCredParams.push({ + alg: parseInt(value), + type: 'public-key', + }); + }); + + return pubKeyCredParams; + }; + + const getExcludeCredentials = (excludeCredentialIds: string) => { + const excludeCredentials: PublicKeyCredentialDescriptor[] = []; + + if (excludeCredentialIds === '') return excludeCredentials; + + const excludeCredentialIdsList = excludeCredentialIds.split(','); + + excludeCredentialIdsList.forEach((value) => { + excludeCredentials.push({ + id: base64url.parse(value, { loose: true }), + type: 'public-key', + }); + }); + + return excludeCredentials; + }; + + const getTransportsAsString = (transportsList: string | string[]) => { + if (transportsList === '' || transportsList.constructor !== Array) return ''; + + let transportsString = ''; + + transportsList.forEach((value) => { + transportsString += value + ','; + }); + + return transportsString.slice(0, -1); + }; + + return { + registerSecurityKey: () => { + if (!window.PublicKeyCredential) { + errorInput.value = unsupportedBrowserText; + registerForm.submit(); + + return; + } + + const publicKey: PublicKeyCredentialCreationOptions = { + challenge: base64url.parse(challenge, { loose: true }), + pubKeyCredParams: getPubKeyCredParams(signatureAlgorithms), + rp: { + id: rpId, + name: rpEntityName, + }, + user: { + displayName: username, + id: base64url.parse(userId, { loose: true }), + name: username, + }, + }; + + if (attestationConveyancePreference !== 'not specified') + publicKey.attestation = attestationConveyancePreference; + + const authenticatorSelection: AuthenticatorSelectionCriteria = {}; + let isAuthenticatorSelectionSpecified = false; + + if (authenticatorAttachment !== 'not specified') { + authenticatorSelection.authenticatorAttachment = authenticatorAttachment; + isAuthenticatorSelectionSpecified = true; + } + + if (requireResidentKey !== 'not specified') { + if (requireResidentKey === 'Yes') authenticatorSelection.requireResidentKey = true; + else authenticatorSelection.requireResidentKey = false; + isAuthenticatorSelectionSpecified = true; + } + + if (userVerificationRequirement !== 'not specified') { + authenticatorSelection.userVerification = userVerificationRequirement; + isAuthenticatorSelectionSpecified = true; + } + + if (isAuthenticatorSelectionSpecified) + publicKey.authenticatorSelection = authenticatorSelection; + + const excludeCredentials = getExcludeCredentials(excludeCredentialIds); + if (excludeCredentials.length > 0) publicKey.excludeCredentials = excludeCredentials; + + if (parseInt(createTimeout) !== 0) publicKey.timeout = parseInt(createTimeout) * 1000; + + navigator.credentials + .create({ publicKey }) + .then((result) => { + if ( + result instanceof PublicKeyCredential && + result.response instanceof AuthenticatorAttestationResponse + ) { + const { getTransports } = result.response; + + window.result = result; + + const publicKeyCredentialId = result.rawId; + + attestationObjectInput.value = base64url.stringify( + new Uint8Array(result.response.attestationObject), + { pad: false } + ); + + clientDataJSONInput.value = base64url.stringify( + new Uint8Array(result.response.clientDataJSON), + { pad: false } + ); + + publicKeyCredentialIdInput.value = base64url.stringify( + new Uint8Array(publicKeyCredentialId), + { pad: false } + ); + + if (typeof getTransports === 'function') { + const transports = getTransports(); + + if (transports) { + transportsInput.value = getTransportsAsString(transports); + } + } else { + console.log( + 'Your browser is not able to recognize supported transport media for the authenticator.' + ); + } + + const initLabel = 'WebAuthn Authenticator (Default Label)'; + let labelResult = window.prompt( + "Please input your registered authenticator's label", + initLabel + ); + if (labelResult === null) labelResult = initLabel; + + authenticatorLabelInput.value = labelResult; + registerForm.submit(); + } + }) + .catch(function (error) { + error.value = error; + registerForm.submit(); + }); + }, + }; + }); +}); diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..a858d3e --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,8 @@ +import type { Alpine } from 'alpinejs'; + +declare global { + interface Window { + Alpine: Alpine; + result?: PublicKeyCredential; + } +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..0624862 --- /dev/null +++ b/src/index.css @@ -0,0 +1,33 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer components { + /* Alpine.js + ======================================================================== */ + + [x-cloak] { + @apply hidden !important; + } + + /* Separate + ======================================================================== */ + + .separate { + @apply flex items-center text-center; + } + + .separate::after, + .separate::before { + content: ''; + @apply border-b border-secondary-200 flex-1; + } + + .separate:not(:empty)::after { + @apply ml-2; + } + + .separate:not(:empty)::before { + @apply mr-2; + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..2133481 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,7 @@ +import './index.css'; + +import Alpine from 'alpinejs'; + +window.Alpine = Alpine; + +Alpine.start(); diff --git a/src/test/java/org/keywind/theme/AuthenticationUtil.java b/src/test/java/org/keywind/theme/AuthenticationUtil.java new file mode 100644 index 0000000..197168d --- /dev/null +++ b/src/test/java/org/keywind/theme/AuthenticationUtil.java @@ -0,0 +1,13 @@ +package org.keywind.theme; + +import java.util.List; + +import freemarker.template.TemplateMethodModelEx; +import freemarker.template.TemplateModelException; + +public class AuthenticationUtil implements TemplateMethodModelEx { + @Override + public Object exec(List arguments) throws TemplateModelException { + return true; + } +} diff --git a/src/test/java/org/keywind/theme/LoginDataModel.java b/src/test/java/org/keywind/theme/LoginDataModel.java new file mode 100644 index 0000000..fd973b4 --- /dev/null +++ b/src/test/java/org/keywind/theme/LoginDataModel.java @@ -0,0 +1,265 @@ +package org.keywind.theme; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LoginDataModel { + public static Map createDataModel() { + Map dataModel = new HashMap<>(); + dataModel.put("auth", createAuthModel()); + dataModel.put("client", createClientModel()); + dataModel.put("locale", createLocaleModel()); + dataModel.put("login", createLoginModel()); + dataModel.put("logoutConfirm", createLogoutConfirmModel()); + dataModel.put("message", createMessageModel()); + dataModel.put("oauth", createOAuthModel()); + dataModel.put("otpLogin", createOtpLoginModel()); + dataModel.put("properties", createPropertiesModel()); + dataModel.put("realm", createRealmModel()); + dataModel.put("recoveryAuthnCodesConfigBean", createRecoveryAuthnCodesConfigBeanModel()); + dataModel.put("recoveryAuthnCodesInputBean", createRecoveryAuthnCodesInputBeanModel()); + dataModel.put("social", createSocialModel()); + dataModel.put("totp", createTotpModel()); + dataModel.put("url", createUrlModel()); + dataModel.put("user", createUserModel()); + dataModel.put("username", "Username"); + dataModel.put("x509", createX509Model()); + dataModel.putAll(createWebAuthnModel()); + + return dataModel; + } + + private static Map createAuthModel() { + Map securityKey = new HashMap<>(); + securityKey.put("authExecId", "authExecId"); + securityKey.put("displayName", "Security Key"); + securityKey.put("helpText", "Use your security key to sign in."); + + List> authenticationSelections = new ArrayList<>(); + authenticationSelections.add(securityKey); + + Map auth = new HashMap<>(); + auth.put("attemptedUsername", "Attempted Username"); + auth.put("authenticationSelections", authenticationSelections); + auth.put("showResetCredentials", new AuthenticationUtil()); + auth.put("showTryAnotherWayLink", new AuthenticationUtil()); + auth.put("showUsername", new AuthenticationUtil()); + + return auth; + } + + private static Map createClientModel() { + Map attributes = new HashMap<>(); + + Map client = new HashMap<>(); + client.put("attributes", attributes); + + return client; + } + + private static Map createLocaleModel() { + Map de = new HashMap<>(); + de.put("label", "Deutsch"); + de.put("url", "url"); + + Map en = new HashMap<>(); + en.put("label", "English"); + en.put("url", "url"); + + Map fr = new HashMap<>(); + fr.put("label", "Français"); + fr.put("url", "url"); + + List> supported = new ArrayList<>(); + supported.add(de); + supported.add(en); + supported.add(fr); + + Map locale = new HashMap<>(); + locale.put("current", "English"); + locale.put("currentLanguageTag", "en"); + locale.put("supported", supported); + + return locale; + } + + private static Map createLoginModel() { + Map login = new HashMap<>(); + login.put("rememberMe", true); + + return login; + } + + private static Map createLogoutConfirmModel() { + Map logoutConfirm = new HashMap<>(); + logoutConfirm.put("code", "code"); + logoutConfirm.put("skipLink", false); + + return logoutConfirm; + } + + private static Map createMessageModel() { + Map message = new HashMap<>(); + message.put("summary", "Example of an error message"); + message.put("type", "error"); + + return message; + } + + private static Map createOAuthModel() { + List> clientScopesRequested = new ArrayList<>(); + + Map oauth = new HashMap<>(); + oauth.put("clientScopesRequested", clientScopesRequested); + oauth.put("code", "code"); + + return oauth; + } + + private static Map createOtpLoginModel() { + List> userOtpCredentials = new ArrayList<>(); + + Map otpLogin = new HashMap<>(); + otpLogin.put("selectedCredentialId", 1); + otpLogin.put("userOtpCredentials", userOtpCredentials); + + return otpLogin; + } + + private static Map createPropertiesModel() { + Map properties = new HashMap<>(); + properties.put("scripts", "src/index.ts"); + properties.put("styles", "src/index.css"); + + return properties; + } + + private static Map createRealmModel() { + Map realm = new HashMap<>(); + realm.put("displayNameHtml", "Keywind"); + realm.put("internationalizationEnabled", true); + realm.put("loginWithEmailAllowed", true); + realm.put("password", true); + realm.put("registrationAllowed", true); + realm.put("registrationEmailAsUsername", true); + realm.put("rememberMe", true); + realm.put("resetPasswordAllowed", true); + + return realm; + } + + public static Map createRecoveryAuthnCodesConfigBeanModel() { + List generatedRecoveryAuthnCodesList = new ArrayList<>(); + generatedRecoveryAuthnCodesList.add("000000000000"); + generatedRecoveryAuthnCodesList.add("111111111111"); + + Map recoveryAuthnCodesConfigBean = new HashMap<>(); + recoveryAuthnCodesConfigBean.put("generatedAt", "generatedAt"); + recoveryAuthnCodesConfigBean.put("generatedRecoveryAuthnCodesAsString", "generatedRecoveryAuthnCodesAsString"); + recoveryAuthnCodesConfigBean.put("generatedRecoveryAuthnCodesList", generatedRecoveryAuthnCodesList); + + return recoveryAuthnCodesConfigBean; + } + + public static Map createRecoveryAuthnCodesInputBeanModel() { + Map recoveryAuthnCodesInputBean = new HashMap<>(); + recoveryAuthnCodesInputBean.put("codeNumber", "codeNumber"); + + return recoveryAuthnCodesInputBean; + } + + private static Map createSocialModel() { + Map facebook = new HashMap<>(); + facebook.put("alias", "facebook"); + facebook.put("displayName", "Facebook"); + facebook.put("loginUrl", "loginUrl"); + + Map github = new HashMap<>(); + github.put("alias", "github"); + github.put("displayName", "GitHub"); + github.put("loginUrl", "loginUrl"); + + Map google = new HashMap<>(); + google.put("alias", "google"); + google.put("displayName", "Google"); + google.put("loginUrl", "loginUrl"); + + List> providers = new ArrayList<>(); + providers.add(facebook); + providers.add(github); + providers.add(google); + + Map social = new HashMap<>(); + social.put("providers", providers); + + return social; + } + + private static Map createTotpModel() { + Map otpCredential = new HashMap<>(); + + List> otpCredentials = new ArrayList<>(); + otpCredentials.add(otpCredential); + + List supportedApplications = new ArrayList<>(); + supportedApplications.add("totpAppFreeOTPName"); + + Map totp = new HashMap<>(); + totp.put("manualUrl", "manualUrl"); + totp.put("otpCredentials", otpCredentials); + totp.put("supportedApplications", supportedApplications); + totp.put("totpSecret", "totpSecret"); + totp.put("totpSecretQrCode", + "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAABgAAAAYADwa0LPAAAF70lEQVR42u3d0W3DOBQAwfhwPcj9V2e4CV8D96EgBPVWnilAphRlwY8H6vH5fD4/AAH/XL0AgLMEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CADMECMgQLyBAsIEOwgIx/r17A/zmO4+f9fl+9jEt8Pp8l13k8HrnfOnOdM1bdl/dwHjssIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIGDk4esbr9fo5juPqZfzKqkHEaUOhO6+zagB11fP55vfwCnZYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQkR0cPWPVsOIZ005o3Hnvq+w8lXSnb34PV7PDAjIEC8gQLCBDsIAMwQIyBAvIECwgQ7CAjFsPjt7VtAHLaaeb3n148pvZYQEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIbB0aCdn2Ivrrn4fDjHDgvIECwgQ7CADMECMgQLyBAsIEOwgAzBAjJuPTj6zcOBq4YnV13nm4dCp62nzA4LyBAsIEOwgAzBAjIEC8gQLCBDsIAMwQIysoOjz+fz6iWMtnMo9K7XOcN7uJcdFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZDw+jkPMOTMYeca0U0CLp4mylx0WkCFYQIZgARmCBWQIFpAhWECGYAEZggVkjDxxdOdg5M5hxbsOfBaf86o1r7JzPeXhWzssIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIGDk4esaq4bedQ4/ThhXPcAro3+992iB0mR0WkCFYQIZgARmCBWQIFpAhWECGYAEZggVkZD9Vbxhvj2mvh9NE//5bZXZYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQkR0cPXVzwWG84pqn3dddh0tXKZ8ia4cFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZ2U/VTxtE/GbThl13XmfnEKb30A4LCBEsIEOwgAzBAjIEC8gQLCBDsIAMwQIysoOjd/3896o1TxsynDagu3M9O4dLpz3n1eywgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgY+Tg6KpBu50nPU4b2CsOu057hjvXXHzHrmCHBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGY/PzgnDlQsfNmg3bUh1528Vn+FO0X+xkeywgAzBAjIEC8gQLCBDsIAMwQIyBAvIECwgI3vi6CrTPlm+8zqr7n3aqZvTTLuvaev5DTssIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIyJ44+s12DnMWBxrvel/YYQEhggVkCBaQIVhAhmABGYIFZAgWkCFYQMbIE0eP4/h5v99XL+MSd/1c+86h0Glr3vlbO0+jvYIdFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZIwcHD3j9Xr9HMdx9TJ+ZdVA7DeflvnNw5PThoGvYIcFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZ2cHRM3YO2hWHDIunZd71RNZvHoj9DTssIEOwgAzBAjIEC8gQLCBDsIAMwQIyBAvIuPXg6F1N+6z5zjWvUhxALQ98rmKHBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGQZHg+46QLjzRM1pA5/T7n3qO2aHBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGbceHJ06/PZX04YMV5n29yquZ+ff6wp2WECGYAEZggVkCBaQIVhAhmABGYIFZAgWkJEdHH0+n1cvYbRpp1yeUT4J86/3xTl2WECGYAEZggVkCBaQIVhAhmABGYIFZAgWkPH4FCfxgK9khwVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVkCBaQIVhAhmABGYIFZAgWkCFYQIZgARmCBWQIFpAhWECGYAEZggVk/AeoXLE8BnySdAAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMy0wOS0yNVQyMDoxMjo1OSswMDowMLyvm1kAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjMtMDktMjVUMjA6MTI6NTkrMDA6MDDN8iPlAAAAAElFTkSuQmCC"); + + return totp; + } + + private static Map createUrlModel() { + Map url = new HashMap<>(); + url.put("loginAction", "loginAction"); + url.put("loginResetCredentialsUrl", "loginResetCredentialsUrl"); + url.put("loginRestartFlowUrl", "loginRestartFlowUrl"); + url.put("loginUrl", "loginUrl"); + url.put("logoutConfirmAction", "logoutConfirmAction"); + url.put("oauthAction", "oauthAction"); + url.put("registrationAction", "registrationAction"); + url.put("registrationUrl", "registrationUrl"); + url.put("resourcesPath", "http://localhost:5173"); + + return url; + } + + private static Map createUserModel() { + Map user = new HashMap<>(); + user.put("editUsernameAllowed", true); + + return user; + } + + private static Map createWebAuthnModel() { + Map webAuthn = new HashMap<>(); + webAuthn.put("challenge", "challenge"); + webAuthn.put("execution", "execution"); + webAuthn.put("createTimeout", "60000"); + webAuthn.put("isUserIdentified", "true"); + webAuthn.put("rpId", "https://webauthn.me"); + webAuthn.put("userVerification", "preferred"); + + return webAuthn; + } + + private static Map createX509Model() { + Map formData = new HashMap<>(); + formData.put("isUserEnabled", "true"); + formData.put("subjectDN", "CN=User, C=US, O=Keywind"); + formData.put("username", "Username"); + + Map x509 = new HashMap<>(); + x509.put("formData", formData); + + return x509; + } +} diff --git a/src/test/java/org/keywind/theme/LoginThemeTest.java b/src/test/java/org/keywind/theme/LoginThemeTest.java new file mode 100644 index 0000000..61237a3 --- /dev/null +++ b/src/test/java/org/keywind/theme/LoginThemeTest.java @@ -0,0 +1,113 @@ +package org.keywind.theme; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.ResourceBundle; + +import freemarker.core.HTMLOutputFormat; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import freemarker.template.TemplateModelException; +import freemarker.template.TemplateNotFoundException; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.junit.jupiter.api.Test; +import org.keycloak.forms.login.LoginFormsPages; +import org.keycloak.forms.login.freemarker.Templates; +import org.keycloak.theme.KeycloakSanitizerMethod; +import org.keycloak.theme.beans.MessageFormatterMethod; +import org.keycloak.theme.beans.MessagesPerFieldBean; + +public class LoginThemeTest { + private static final String LANGUAGE = "English"; + private static final String MESSAGE_PATH = "theme/base/login/messages/messages"; + private static final String OUTPUT_PATH = "html/login"; + private static final String THEME_PATH = "theme/keywind/login"; + + @Test + public void shouldTestTemplates() throws IOException, TemplateException { + Configuration configuration = createFreeMarkerConfiguration(); + + for (String templateName : getTemplateNames()) { + try { + Template template = configuration.getTemplate(templateName); + String renderedTemplate = renderTemplate(template); + Document document = formatHtml(renderedTemplate); + + saveHtmlToFile(templateName, document); + } catch (TemplateNotFoundException e) { + System.out.println("Template not found: " + templateName); + } + } + } + + private Configuration createFreeMarkerConfiguration() throws IOException, TemplateModelException { + Configuration configuration = new Configuration(Configuration.VERSION_2_3_32); + configuration.setDirectoryForTemplateLoading(new File(THEME_PATH)); + configuration.setOutputFormat(HTMLOutputFormat.INSTANCE); + + Locale locale = Locale.of(LANGUAGE); + Properties messages = loadMessages(locale); + + configuration.setSharedVariable("kcSanitize", new KeycloakSanitizerMethod()); + configuration.setSharedVariable("messagesPerField", new MessagesPerFieldBean()); + configuration.setSharedVariable("msg", new MessageFormatterMethod(locale, messages)); + + return configuration; + } + + private Properties loadMessages(Locale locale) { + ResourceBundle resourceBundle = ResourceBundle.getBundle(MESSAGE_PATH, locale); + Properties properties = new Properties(); + + Enumeration keys = resourceBundle.getKeys(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + String value = resourceBundle.getString(key); + + properties.setProperty(key, value); + } + + return properties; + } + + private String[] getTemplateNames() { + return Arrays.stream(LoginFormsPages.values()) + .map(Templates::getTemplate) + .toArray(String[]::new); + } + + private String renderTemplate(Template template) throws IOException, TemplateException { + Map dataModel = LoginDataModel.createDataModel(); + + try (StringWriter writer = new StringWriter()) { + template.process(dataModel, writer); + + return writer.toString(); + } + } + + private Document formatHtml(String html) { + Document document = Jsoup.parse(html); + document.outputSettings().indentAmount(2); + + return document; + } + + private void saveHtmlToFile(String templateName, Document document) throws IOException { + File outputFile = new File(OUTPUT_PATH, templateName.replace(".ftl", ".html")); + + try (FileWriter fileWriter = new FileWriter(outputFile)) { + fileWriter.write(document.outerHtml()); + } + } +} diff --git a/tailwind.config.ts b/tailwind.config.ts new file mode 100644 index 0000000..cb7d1a0 --- /dev/null +++ b/tailwind.config.ts @@ -0,0 +1,37 @@ +import type { Config } from 'tailwindcss'; +import colors from 'tailwindcss/colors'; + +export default { + content: ['./theme/**/*.ftl'], + experimental: { + optimizeUniversalDefaults: true, + }, + plugins: [require('@tailwindcss/forms')], + theme: { + extend: { + colors: { + primary: colors.blue, + secondary: colors.gray, + + provider: { + apple: '#000000', + bitbucket: '#0052CC', + discord: '#5865F2', + facebook: '#1877F2', + github: '#181717', + gitlab: '#FC6D26', + google: '#4285F4', + instagram: '#E4405F', + linkedin: '#0A66C2', + microsoft: '#5E5E5E', + oidc: '#F78C40', + openshift: '#EE0000', + paypal: '#00457C', + slack: '#4A154B', + stackoverflow: '#F58025', + twitter: '#1DA1F2', + }, + }, + }, + }, +} satisfies Config; diff --git a/theme/keywind/login/assets/icons/arrow-top-right-on-square.ftl b/theme/keywind/login/assets/icons/arrow-top-right-on-square.ftl new file mode 100644 index 0000000..81c4bf8 --- /dev/null +++ b/theme/keywind/login/assets/icons/arrow-top-right-on-square.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/arrow-top-right-on-square.svg --> +<#macro kw> + + + + + diff --git a/theme/keywind/login/assets/icons/chevron-down.ftl b/theme/keywind/login/assets/icons/chevron-down.ftl new file mode 100644 index 0000000..673ef11 --- /dev/null +++ b/theme/keywind/login/assets/icons/chevron-down.ftl @@ -0,0 +1,6 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/chevron-down.svg --> +<#macro kw> + + + + diff --git a/theme/keywind/login/assets/icons/eye-slash.ftl b/theme/keywind/login/assets/icons/eye-slash.ftl new file mode 100644 index 0000000..74a9f78 --- /dev/null +++ b/theme/keywind/login/assets/icons/eye-slash.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/eye.svg --> +<#macro kw> + + + + + diff --git a/theme/keywind/login/assets/icons/eye.ftl b/theme/keywind/login/assets/icons/eye.ftl new file mode 100644 index 0000000..0bd4d06 --- /dev/null +++ b/theme/keywind/login/assets/icons/eye.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/tailwindlabs/heroicons/blob/master/src/20/solid/eye.svg --> +<#macro kw> + + + + + diff --git a/theme/keywind/login/assets/icons/header-logo.png b/theme/keywind/login/assets/icons/header-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aba90715c1f99426efdde30d71c5b3d30673a8cf GIT binary patch literal 16932 zcmV)KK)Sz)P) zcbp_;o&VoYRdrW~>B(Vp0yeWOaTOE+MNtId)Dt}ec%EXqJN59q#?uQwJ+q>K z%AH~cL_m-nH?cX+?oOWR+*S4b{`hw9^z>BqbocbKi|*(3>eozH>Zj84&7ZG2=fZb! ztP#nMabW&g>^k*Q%-jT^kNIyt>&UpcXDy&_@Ci=+{`bfw+CZt}J*wl0tAQ5+W573n zUB`1UN_$vNmdz_)$!Pa-%-s0#9L`CcL@k&DybL%G_$hE(U3+T}`c|QT`#*TM{nc#7 z@jl?C#qs2ToxrWYEu{^t*&O`@!1cg~fGqF<;Kw!Y7X!`!lE72PW@x|HxCMAk+4uJY zZ=>wNJBgDxi77|`tASI13xU&t^~hWW&`Z67Bou{-L+FRT+31)$fFA<;fqw&jTU`EH z;O~Gp0uDIzs*0ai|1tMw}2ADI*) z$aeZ;DDxRi`>cjWW*CsofajtBrGIZFN-JU+2I0@1t%01xNjwLz1UL&=OLZXvjVS%; z5mK)|Feh^_zGYMFoDZ~HNcxrOp8Q&U|3+c$oG8uI^4o1P^!De zBfO^g`6?nY9|xi+K6P{pGX%<%IEH0|WuMBloHa9Dm%6xU$Ygto22R*1yDO+hpBG zFQlP;0mcRI#QVwL*0bjv;B3T&1@d0s3w*Tr(ZDspw-KfO1QjHf4cT!R+ySA;eA*X& zg?JZe4QOz(P{>llWN=;alLKr}atzA`uK_rq73@EeUmDGbjgo*E$8 zyAquET=(KbNToGjy3sAg?VoKeA_Oc%CY+Jt?>kkt4`xtO0BJ3_Nj{E-N zx*q{=IWYwZ3PLgT-iKhkKgpccIhE+MF$@UBp?yBYdmx_#*Qq5t%0BvEv<>>7Lhra6 ztf*K&`6RdnuoKG&$4^Cj+mCMVy5KnCy2=+I9*0v`qk8+m^B_5aI^#^}TZq|zh(h07 zcD(#b&iv9B2v1CqPbBIUCNDtD-Dd+=6#wRs_|i9+T|itT{?q$?*4>TxT8|4fib5#L zsXKp#YuOAgI2SU*m`=Xh^K&y(wL=HFRwbcQj?ztzAu+uFYToE;!bQN(feFO*;2}a{ ztZZx=c^A5Y`9K7?7`W@%9ct5IA_3}sh{E+;M$nu*(a_O62R*zSXxv zu;ZvXYhb}y;-d2EP^h#P0g{~nXHeW{p(upofZl>v7$={HR9d!=#vtB;TC^DE%!Nfu zPzx47EG~k?P-2}751}m+YiNMvvgK^O`WjZ;`W=+#l51(EPJ;!wFPw48va` z`77W}z$(Ptk5Zej`cHWF1<4hNdDU9{)Pntp(0Q)GM6B?0flCl~&@$j9Jog1jC}4SG zepqEdA%h;=fpPU`@cN%dkL;OguLH>QUcy`?Dd{c1W58v=L&bGx0ERjN>PXfjDZH;c zy2NgQp`8!tJr6#Q^e{NtPZExQ0PTt8kQ#(Y8*0N_A<_zk3^hY*u;Y*#hW(F>>+${{ zQOIn<$!`O`hY{AqTTyfRVEzK==|#1+L3;_!(mIfz*g=tR0C_bO5IzT4~@_LR^Ah zuXnH&SbzwU6K1l~%D{56gbEqP+7{41?@R`JR{ z9;#t0@Rx|o;%VTyT1@k4;E$OuFi+#TFG&6d_-CKxA4F1c8-wRS&vH1j1^0`ul=w+7 zLWuX^^N6S7d&u0e0#Oowj3hH{MO^Xvcv>XSLj=gHrmb=FU`5VTb5_TRwx#sGNB)9| z!=E7(g?RTVs{7QBFmK((*e&%55s--@pMsWdSoLyCWkx-+<6kD1JPd#rg=KxHa~A-n zxU=#(ac!kjQ;+2*6qG`_F4o`x<11G4*xUb%6}Ntu?#)k=?(V@2+x5D-s=e$#1Fo&- zU`2Ew*2g=6=liTzz}FC$NW)3!h{k(DL1_=ivT@B2ZDadsAKS;+fk)YP+NEUL=3}OY zf`mzy>F4u(AO*bHXZve-_5{g`nJPqXM1r^*Dz@7Q{NJ-Qrelef_*-2K=I%cyaA;P0 z8x{;a1HH>J-}!UAZ@eBo8u)q^5CQRN#2fM;5`P2u39uQdA-N5)1}}V8(tnlqaLq87 zVbJ;#WCFY&KOq7VNRM?Y=C6O8u2Zg2t1pkL)2}+9)?C@D)?RrzYpz&I+x%j{y`d37 zZUV9sF|5d&Xq$hCIcsiZ&YE?!F96eqiE$Vjgz+)RX2p$F^WkM8vW^_0(Avh+Z+Qp1 zFS!hRbcAqn0&UcF+3hOp^7S033?qnuI3FqM48k`MH{0(NB%4l=jkc4u+vphG!@4JL zB07E$H{L06Gkl2e;3nWsL~y*MY~4AC(EeYWyen?J@Os29-yT!MI^Ba?R}8!_!9D|U^j%LA?ra-Plg$%{|KPP`pKst zH+B`7u_qWG{~EdM;-)0s7zUw{VaR3KedVj!bj`JBr3g=q*CR|ufgn4y8Lo-{hqwuX z@VO@Z#)%27(Mpkw_YiWjtb6>sM8^-|M%sd0kd+J9Aem}Ae70SV1i+sSTw3=3?T8Rr z;GMqaQkvAj?;gyy4dY7)oK(#wB%0&Q9FkIlSx6(;xZzixR^-apT>%p?Gca z0;Rxn;uO*`oE&&Af$u}sgRCo;yw`#bL$a=N-prX@Sr0NUYJvS0wIuosj{YQ?wpvcG z8nj_xWiprpM;O|00UNKm7Ns>-CQ~aH*BHSs$bs38uZXV@oVoKV#5ejo3#C0Wk#-`v zF_vw=9RO|A}d|3^(2-b}cdNw)(?W(`O>cqM*U(tQ22bCcf<*H+M^Fx<3X zFhel73p@wo+M8z*CO0E)+W$o|wKf4?L}I9ql{PX;g$Jci8BPVhjN}u44e`al0m;Dm zu2Kru^YDU&!4<%-fjdCGxDblcK7NpOPu|SZ%|FI)bGY$tJi}}x06htXSRH8>+6~m2 z7S!o&sMW2gwXLZ2t*CZG1We^EQb0jN%7GRGwXOx$wLwcbjH5q*T)4kswp21op*#=s z;C?37p26;mF2x=nt5rWtAt|SRXx_sm{?H)2yotYaLPBYebgY}skv+5xZO4lSS|#Nu zJr_Yq39m&my^bZWuJ~T!WAdAjW~!cku3*4t+3!kqsb3Kr_@8s*FfAC_58ACon79b% z)~6ARq}_ zjKb;!*m`P2!3B~oSQ@n=jykg)`l684&4F>rFVSS2Nkek-D>RiX_k;5t@NOcf;e zAX$6he=loI3qH|NINk#|h6pM=Y<^QI>=+zm_t4N{!!SM>v+bi( zT;){fX-y;)y11uBC``0Gpw}X`2R9)FE7PE~#x*RGEj>i?DOPUz5v!iOiEwrd*KTc0 znB+WYGht1e#8y%cxW(gW4aovTL#VDWOytFKNxR^>sKqww>~>fZ2TwuDm3^kq?TZm# z;S)$*N5GYt0ZL(J(h!TW@B9lZ%Wez;z+u2JMu=A?umm~YAGar z^@m6b@@(N}p^sCWpll{j_afx{&qS_ANwLcz&*?)*%J@#Ir2SN2w!*%1}sZVK0>aBj5jk~m)3HjLpB%+r3|z(-mDL7|D`v4_**KLK+Rb!)=-TW zm6^}uwYGEc?B~(8dzV-x)vsgF${-7(5p+OcazW7VECxP;q?MkISf-r;+wQJ$92R2z z9qZUaIr2yx5VXcqraUGy-_P!lUjbRjXO|82rJD^Z@UbsJL!n;)gdYy`ZD;Y+O`lc6v51=aU!jydK1Yi$fr=A8$8jL=<}kcSSF)RaS{L= z54ENR7RDh{bZJ#$CLt1S0Vj_hJOKGDT5EJJgYMsTfgbArmT}5DRAde0QdJIAc|8=y z*a(Ab&t&wG2WZ>7yB4d&4?ZWlA=9Mb)<1VyZk~c^v+K0;IXvfdp+M2zWIQ6D#w=uT!Y#yy zchfbz6E_rLJTZ@n&ZU6D%$1TEs?7XhW72RQEj$%bw8-~sfW&FJK)97k(3 z8WplHR-JP&=AR09-DrI_qLtRvanURk@Y-zp&)z`$?wz$*C6(|9oB$g_kaIMPWZ(H= zBQkNeArspi#LV|g7p}_5P=>`!r=oX|>e>TH>gOil8APMCkx8?3{GsCiC3jp7(b%3O zSWq5~Z)g;T=inI@7$GWTMWu;S>GJy#a=j{Z{$GK(e`?n@X2xsF{@;ZZj+JA!?i&Ss z7=Px2aug8P%{|Dy8A7z*1acitL0A+j-Lt14R@8NrtifQ+s!wdiaq1;MT#8(WYb%yd zAeP2Kxy!A)4ew;#lQ$D_^SFkEW7!OME@AJY^GSCsh1?isAye!p;RA)l zLmUs)8-k^AXbJnL{?2@5AeX^=@;B&04wWd*ZAzg~kVz`l(F3iW^T=g3GC4^-jpSZ` zj4J-lCRinTYM-2I!CwR{|9=F#wo0tQAbdO^?v`KpZ0lFF=ZDjov_`ffTHs!$Qf=3Z z_Yy2bz6<<)>5G9zE0c-DTtC;=OfSGV;{pTd?8g{g!XG2|Zz~dWcoWkbs2wT(MiLQP z9fw|N6ffalw_lufB)GqV8gPtfmc_q%S}$xj$mM08JyYv>*g2hvhTaKOn-b z5_#m_=;Byr%IbU_Vx>)Gw=hF6wjUCGn6LjT-uK^w_h|J?XE~mSQ_LJvfE@}Ex9!DB z7+|mQV4mx`WD13b9jy6qjJ_kA8SXw6r=<@sJ%r&Ey$@RBhN57{={xi!wpU<0F$bkJ zhIZ&ZvW51My&PC@4*M2vz>W7{WQM0|@TGc?tPAZHYEc~eBC;aWfDi$prw>Ii7OlYB zyS1NO=10Izt-Tc58^tNyZgkHF(>jHGw!KU+t}TAvisW5?KIkWAX_Y9Nm;U=cq;9AZ zL&!s04}yv(Yn{Z(T~L3|>?zJKM3{*E@HFD@K8kQ|f{~8J4EHQY<)_uX)pB#b!*oFc zQdiY1LGpa2y0yMt<9?-HG_~G~`w?OBvf}qmh)d*W)W@T?3(=l`iCDLlX~;Jt0pg%> zRray*)55ceRn#o}3-H%v-!~$2Vx{F*j@;vDn8E3#kXWrW=6w6CBfe2crB;RsIYMCXS$;JnE{?V9YxM@8|yz$Za@f z&>EIIuKPa6b^n+ONjjS-T|N}2ZQ>y7AG?uV%U;A#?<(Qm(jFKleCywv&!^ zp^BQIr%X~s`if;c@1kpHJ9`#iz)0U(aI%>BiDK6U526aSJO=ZlU|S+UT(9wg7vnN& z*;ogWT4NKel4fL|yoBIl#4D)Z z*B%sntku6>tUY2MQ?rm7fdzakVBG+fDalGPXt_9K%PL6eR!5?1bUth%59Srp_-5koZQe1fhP+)dphi zG)ll%j(=mSh5iFXd#{%nU{yr>cJ!h#RMxi|B&G$ zn;C6eKp_+*oKMj)w1dvEedO%~u3;S&B&B^FGfbhSmzLxJYc~FXL&MwIvtR>-tPNzb z7R6ve6k5aL+DbaLrt?-Av=V`#JyhqM^%%y0f*V2o6xgZJ%gAQlhUZ=~gB5WWqA~sn zax;HID15ZttEn|!qLu#hFQRS#H&CuC?R#q&A+xtgZouEn9!AXiYVL+01jPYrB^O&+ z{QE6tUl;IYrqYL$;}ul65yJTtV{P*p?m88f9rv>iYe{j>BdoxGTCuzZ3D`EnDk-l` z`JaGo{I0i6{hUp|MS4-JWNOVyqj&(RHLDDaUr+6V#P7Lp7DY;>5DBs{>p}T*7L>SB z4K9-HRjSWRBCfOABH{A;Z$=cW*ZZtrUp(IQSg2tNA7TGf(zf?aH==*~w|Mvb#}wDE zHIzzyyf=~fV9s%HT$ftXc{N}e1|icty1nDNRRi%#dt~hv49}x;cqiS1&)_K&L%Vop zm`t=oQiKCiE|u0~qV1U4rSFN`Nj&ucL$7-mdzUQ4iDa=tArT-@lK^oF#m@01K`h*430|t0C9CSn%z?B&esSb=puxX7~o3{{(cFU<4^AnGKoDr zWr0 zpLLfJm{g-gpp5N@^f2n;8!%711bujm^oPn#U~M^g@OjD3PL_0c6EaOQ`Fx--(Fj>% zEEFQ^IP{N=kqKy@vGq*11Y zYM6&4UX;U6dv64#@it=NSK?F1^VJAE#NzVvLR{#xY$}u~F_MwJ(7Wm=KbKMl7KZVE z`v(Rt9M5Jst*?(3+a{II`_}0hN@1HO2gb%YFg#2)mpeM??jIdxZd)6RIy;FJGrVT9 zZgefCgJGa^ISRY`vHE)Hde0xzcGW8h%?mSrKr`Re^sYaJ&HD#*?YgX8His1pdWc8Dc%Eh~lVktj7#sH;A)m@%#v;ur0WKCZs%Q&(YyfZD<9I`d zPPI&M-bDsyendfB6%)TgR+&_fplKGi{=tQ`k|In8=yI< zp5MiPB7F$S;FQn#j=o8r=W$?QfYD5bm2>70GR>peU=2Yj@H`6p4}f9O_UbEW zf9+L7PVdDXfZX;h%2bSLP1rIybJ-l`ceU~4u736(8Uf3|vcprX3on~v<)UuRUp=4E zl*?#3hXSJE5bKxrv81F_dBA?b(dC^JysLQ1MonETi;} zZW|7hx5M>zPXr0zR@PnAigv^|eFG98K7eGW{F>_3x7ARE=l@y3dlAjQ5=jDBj7`^} z5Q=cPZ#9$bD!wwJvZ%4zdH$H`f&|1Z(WoG~n8`jP14u?y5d6lb1D4lhJ#?D!pCho)p&cHCS3pUX4`m2dwunL`p{Pr9uEi@>IyQ<)N3{T|fh)1|+ z-7c7DbhVMrLpJXm^+VcJ7;&J_EL67N~Q(a7@ z*(g8Gg9ta$7pTvr(JVfvMz9jel=H*o1iU16KFLt$Qj%>8F>(`BIfcr)ooep4-yp)c zvN-dVh)btldJvfEufK`IcTbSkoHw>fr5vu%I!H%Mb z58-Wk5S>Y);t9Y=;kwtO-EWCKQi_jgu%omMjL|%-ad)*KLgW%8UQ*fHTNRgWKyu*!9r3N6=m=^s^?s`Ql{JIi%fSqz@_~ZHV7f(8 zty0~kqS&#B4kX#3*4mE}EJSlIp|ZB37L+E7W-=l)6SH~o8WoT)VKP&&gj;F8u$nCn z&^%Y${Yddc7B%9Bd*nx*F%Q|mqZ!dA% z#nU!O}OSDp_YR@C*x{cjg$HB{F>G{hK(DlZ%$vy*xl(?}(hy+6^g{L(`$t;nO z#o4FLV^y}mXex^WIukJ*Pm^~F*ddFU9YT9rLKL3I;P?bj?K#51p>fPctr61#w}7|# zK}e6IqAid~-G)-{!V2#rY>S`K$%6(RvM{namh3rzHWbgp5&qzlaM2zcO)gFBv^u|~vDioD~JcZBl3t2G8F@&$3z z*&&Nu!C~8hK~lLquBS=o3mh3sLBYk0+8CkrBwnt7*%HM_ zBv9cnhUYQ(iBB_e*I8JdohZY^Y;Pxe_IjdATW}6Kcm+o?vu1$ndARw>dCxEu(Qt_0 zKC_<#JNqG4R4NUH3R##jODu(&PDKlqK&imc$wMIrRv2T&*{C^7hE+>j8}YVxq0|VT zdk?N74@4viC`_O*cQO6z&tcimZ=(>OiIw`8Vn0%px(#7mt;BhVZ~nDD>t@0%{e^*O z0dDbG?jb?O-+L5BdS_MLw$wUE{U>Dx;!fC)N zq{d|hV&S$Uv7n${I+bvlokcQA{Z;MHXL<(MFcKp<(NJH5km~SL1Px}v?mW|u-z$FP z^|CAm$HzMpwtZepI83Ta%}EfHY2qc5I0M6&9c|dFmSc6blH0Z)ckl>iM+d}W=wyoY z_kV=e-qCin=KOhdT>E<3Ui<=#aV^$Moe=MwrmH2&fsh3ub878LEmMWoLbq?nAfG`G z9ReqhYVVO{*%X9qRNtbraq>5kJ?cs?AlV>)iD_j^1&=B@&cX9uK+mS9hzt!lZtnfYMFz|rI^9Z?$MYwA4G|9 z5w#1FS2F3=`Vo?O(_0 zwW8@w&uYK<#mRhRY;4%|yr?C3y6BUtmNUQ=&mghMxc81;#Nrt`}4$scU2>0CNjVC|w_JmBe_ z{S@+b)Q%L>dQk>?|2Dk--H;xaD*0#}bM*#j?Sx!fC|0H-1o}@gtV?m7bMV|WD9l0* zr@NQI6{}hDt6!W5f&?Tj_)>({y%PU|u)o%$p$D}Ko({x1OF~R) z!MWo1tC`Nr_H3t(`}H>|C9E7T1oh#WjgYMcvq=rFUyD$-&3G#H^rL(BtX)254qdSr z>3km7^Zc!oqSo!~KY%t&5|_V}j%%(ade#EG6u6_{9C5K%wqUPZLHgeNFgrV^`IeMv zqLso7+n9E^q4w@2xSmJ0;BfY`In3*5;qjgQ92ppckVVK2`B%nkEuAFet?1M^-u5TZ zhxSNt-Ht-YMvo8S?cavE?uF=_k7832LawvQ-FW}GO zImF`Y_m!av3{1*Yea4<{IDUo6=TGs}&8O)yNh=&c2Q z6JEVqfPp{b_3^BMg2tb*^bZckRLK>SFH4|DMFf z=TJD@xTi!Zh2v>PQaO6t;=E-2scbzk$Wwa`lb=YVVi7FUD06pt5RO9F#_QjOxBUr7 zCn26Fw%FBo0NYhddqNK#dV@FIkI}OLJuy;Dmj+NmlcE&f)<FDKP?N|9eHaGs4L z0pmt+Gs2u(dGO1bS&+P%$twLH(qNu{85+^HuR}85DqV(=|lb z^ikMXUQ^N-N_&o{b6BRq>5F?<(ACP5yAQGJ;1C53R6Nl3PDR7 zX#F#^{tHSypiK*$!WXA;(BW2=qg>`Xm*s;8~zv=cKo z5#-|PCAc5`OxS_2zP`9(`K5@XmQY5gH(7{AfB{pI1Yv7X1WS(eY8LrUoy5-HK+6kPq4SX2 zl|v~#D1z>eKdF8zS_)NeMZzD1~xUdd2PjiLK@Lq022@0A*yVGt@5upEbiHRZM_{MkC6 z4eUfxX#J?z=RC_}DdDyFPi(i*01ZVt+DS`lfaP0$!jtP?k7tI8P1l-^TbM3L79&CT zUryUv(7`0#OFxZKkXNFfXX)EaXTL2VWQO0L#Td?Kx^gm3?PQkCsD%lNIh-)Qq+l(P$kz*n!etxx>}7r|#>$soO4nQd0B>a<-VkKBNkL(?bX{dCobfD1 zHbmQ1FQoOAFGLr>h=DFZ;h4xFbVT?J35IJXAO$LPYCtP}#Ll zDSC!RupF0sXxcMA&*zt(4PR=hBHj-{%Y$xCGbI0f;2S>6hiQP0FNdr(E=s7O>Q+)b+=t=~gM zk({=}gvOKf433ZuPqW%J{_cnb$A(V39Lor9W)zfbA9SIcAxLh;-yLx!v#7ZDlz~=? zx&2QFD}mvw{LOaq+K+#A@=JY|l~6vB*PCt~gj!yNi}5e;d^58bBH;f_xzw&4HDe;| z$KL|#VD?HwvyrB`?A%QkB(t?hCZY8|sgQNAwj*EZzw@poKW#~H=BZ0L<Cl8iA!2cpfg@w=+_8hh{r%*!S?p+(1q&ClYV~Sju?U%THqa{4S`&{) zFihC^)Ha@c{0SWGV)gV<7#Z1(*4I;=ZM712BV1K42XzKgwR;nOdFrOYf`dnhM4Vug`r&}(;4d_0%Ub$H;9Q^OpF}c-8iqoXvlDa=ZKrj3C*$4A zvC_kpR!KAb@;5P^By$x~7*|O#zJy6e+U-aRaWfFqySp5I%(wT^yh6yA_$*6N`!muE zrDPCz66w!VjxNOYc3TsEqnS9NV>iHxA#4ap%krck-&yi zjl%OZk%*0Ln>_u*7ViAzFL~zar^%$#DAOdJOtSIehq?FeyD2yY!uE8xsMZ?8FzD!r zkWOc~`_6lKIRF)ZsFz#8fkBIWog(yZxgR0agizB4oWG5{_ZeZo*B|3oefp{}Ed2FB^t&Mxvwhp}~P8-2Stl zvt{!xT3SNbcDTlvMRnK_i^m>)jNO|y67T3B91af@3WXao>GYChGWp6}E_=CBY8hes zKgPyJF-rut<>+Tzbjz*^MJLp7|U!B zbbp!`hB#3LiFQ47HisS`htVVCM@Gr!auo9U&93X7*V@+hUjPr>a}N*P{|KN7g=TkM zl#*7umT7|Ld8vtsuVpit6`_#z$-cRB$CjS5l-9O(Qpw~YI}&-%@X*jd?A~>lXv`!M z36src*t&H$cmDDYc5K-~ERi4@jiR-FA5zqIaQ0WG3W~9sg$Ivdcpjb^cq<%&vssR1 zhRLgtV0$G-@vkT^A?P7(BtQQvOr2m$xQ}DdAEjiKbPnyHV_+*@c*gj8BYx|j;!oFI zZk4>Y?AU%5%xqBY#f#(Lnz>G%!T&{V(hhJnuKVR!_x`7-0N$gy512!~cI0yx*V^7jBGF1b z(Ly+E;5wQ|9(OwN6YH=g`NqCR??}vl94L{Pv|+9%6R(*TiJwqvL6p`bjU3R@yLJh+M=T2M?btnC*zIkEBQ|YIm$2X^FQWIH zvk1k(E9qn!Fu;mQk0!SOZVsF*Xb0Sahte9`j?j{bF@HfH*{sX(@bLb@!-wDA(bfG( zKJPA=ZO~mQh39!BCvpjdvg4An)jE~R-rLq5dDZhTxM1Y2JMX}83U7?X<6lM|;2|U@ z{&Q4q!`eiYgotgkXzMPzhet_Qw??44_J1sj68{EiO z%&NJwT_ml$l7p%X5#XO|a6BJj^4YloaT`~d#+0+-$mcZAY~8#e zH8Mi1y&cOs+Q8~q^u`Dp4B9jx8pX)vIqj+K%so6vIu^k-lwW`LO8E6mDB(Q_=hc%) zv!h0WqFsn<=fn8(XKgI5-(JV@{IH~kecy$D`YFIQNRNwVVF98Yf?U6YmYYLs*s}5! zWLx?$Qv>B}zL7vjVF9mvpQxHB)0&cXS&wfiqOPg18lBg3@edm zs+_u}lm)1eds+D#wPs2M#VsyJg84!2nO@*_#9}*>$@gU(A;-KoV881SMvM2;SQ_*> zh`ad0;`iS&y%4g5ASQ`s#zTWm9)0)``VSt!Gz=oqD1CG1uyWOETH7KdC-QhfeNKF!wMHp}wl zFGo$QU`~p&4r}|OK`_a+NCT8$U#9bIfemR@-9V0jvG83&%5_mUa8CGH) z@EBsr-GW#cyuA%aQ^|$-LQcL zi+V|?T=MzCjKV}~P1p_-iy7?SdxVD{e2DR}QCbp-wqq_pO0f@N1(s!!mQ2TyA?EcT zp<{RqZ5Slu(OM`_79q6-VW!fES3@U~Lh4uCRxj>GUZ|j0g&$fFGQP?NP9>a)Oyv8S zE|}s}j|VJAIx^;viEJlg4HOXV(?hhZ0+U=xX(W~P1&E+rL9pBH{!k&ySYjRr=bs6= zBxU{EL&anIY4Yswh`qdHH$b|fNNI_o| ziPgD?Md3F|y^-l`!G5W}^N~ROOw7XfA+a34K=@fmi{*Qf=Olq7GAt^t9|6w5-!1%U z%M!M z6=zmtGHLqe&P{H3{@G+Q2893tV45bb1H*%Z7>O1v%i0L+v`w=!5{<4;r&94>-F^qB zpRta$XRIL|BAq!-I4Wj-WJTBjK5{vp`<*jT|3}_5nnId>6?osull=#4ds+=@MR!Xs|iN zYWg;l!P}Kc>?#PSm96)q6PYcZ4ChnqU3eaamOjknkyB9W?~qC80{kaDyNtmyu^f+8o43Kr7 z(pZl$IYHOkwzt_>7tIVmwR73U99a57%=GXdB9nY2O6OB5-tvo)EFhS}$qxfe&#-zo z)hC@we4g4|Le=*F(|~m!LegXF;Yv#)*-jrJSd)GY;vTDp+nG*sS&o+@PfDp5Xsy4U93Nj4jmJ56!v>Ztn@1+C$!2pX#Zk82t(&&-#AA0+^d!H>uE6)EJPsGqjA`XufOEpaS*Mh#N6AB zxDgCQ$P5DekQaQmq>ly?Tz8qCRZ=NPC~g-*Twp0CQy=4qW;cNdIg{pST^@36x{KrS zieu<1eyrkeemj~Oads`eko`+9#LSFzAupO)TwluYD@|Cs_}wlZJ5oF^4+)aj!_9U9 z;(kjNk8dCoL_LWUuR$`N_7=}+XK@V0H|}UFf*2B)(8clgAj->6@TYDmVIGogbT$4N zbtP;;tl9r!=0t&Ii1r^vl!`&b0_Z9(>qO!f9}GG`5oaJQ2SEZSiA>h-qp{4VGmv=9 zWz^0WH-JpQ|4nt;{Z&lX31yfRx_RUtnZ=KTJY(gFEZ?WG!d!&}`_E%)OvFzZZ(?c! zNbo_MDM+B$anN;tl1?UH-qz8{id8GqFdogNUo~CM2n0wumAY&<4Z;UxEm`5Ta;oMG9pfL|*Yrfs=ydIgFEnG?bW2MMp6gM_7l_z4@s<{pQuk@C&!9%C3$69%P18KHrM-R2;E^NT@r&EJ z|DJns3V9N3Z78LFrnO#46NSi0oWx0-L=E`87b0*BY2=Ie0IuzNj-$$}Q zE}(ugw8w!}(Rlo;uIpf!29an~YpwqrF*zIJh&hRqIEj-uiP@o<9QQ%kL~uq({m}ZY vmSsH-T&=Z!H_h$Ua1tkR5+`vIb>ja6cI+{GKoho900000NkvXXu0mjfQQ^`+ literal 0 HcmV?d00001 diff --git a/theme/keywind/login/assets/providers/apple.ftl b/theme/keywind/login/assets/providers/apple.ftl new file mode 100644 index 0000000..2444359 --- /dev/null +++ b/theme/keywind/login/assets/providers/apple.ftl @@ -0,0 +1,7 @@ +<#-- https://apple.com --> +<#macro kw name="Apple"> + + ${name} + + + diff --git a/theme/keywind/login/assets/providers/bitbucket.ftl b/theme/keywind/login/assets/providers/bitbucket.ftl new file mode 100644 index 0000000..068bc73 --- /dev/null +++ b/theme/keywind/login/assets/providers/bitbucket.ftl @@ -0,0 +1,14 @@ +<#-- https://atlassian.design/resources/logo-library --> +<#macro kw name="Bitbucket"> + + ${name} + + + + + + + + + + diff --git a/theme/keywind/login/assets/providers/discord.ftl b/theme/keywind/login/assets/providers/discord.ftl new file mode 100644 index 0000000..8ebecaa --- /dev/null +++ b/theme/keywind/login/assets/providers/discord.ftl @@ -0,0 +1,7 @@ +<#-- https://discord.com/branding --> +<#macro kw name="Discord"> + + ${name} + + + diff --git a/theme/keywind/login/assets/providers/facebook.ftl b/theme/keywind/login/assets/providers/facebook.ftl new file mode 100644 index 0000000..bc692e7 --- /dev/null +++ b/theme/keywind/login/assets/providers/facebook.ftl @@ -0,0 +1,8 @@ +<#-- https://www.facebook.com/brand/resources/facebookapp/logo --> +<#macro kw name="Facebook"> + + ${name} + + + + diff --git a/theme/keywind/login/assets/providers/github.ftl b/theme/keywind/login/assets/providers/github.ftl new file mode 100644 index 0000000..9523103 --- /dev/null +++ b/theme/keywind/login/assets/providers/github.ftl @@ -0,0 +1,7 @@ +<#-- https://github.com/logos --> +<#macro kw name="GitHub"> + + ${name} + + + diff --git a/theme/keywind/login/assets/providers/gitlab.ftl b/theme/keywind/login/assets/providers/gitlab.ftl new file mode 100644 index 0000000..4acfc13 --- /dev/null +++ b/theme/keywind/login/assets/providers/gitlab.ftl @@ -0,0 +1,10 @@ +<#-- https://about.gitlab.com/press/press-kit --> +<#macro kw name="GitLab"> + + ${name} + + + + + + diff --git a/theme/keywind/login/assets/providers/google.ftl b/theme/keywind/login/assets/providers/google.ftl new file mode 100644 index 0000000..b536cdb --- /dev/null +++ b/theme/keywind/login/assets/providers/google.ftl @@ -0,0 +1,10 @@ +<#-- https://developers.google.com/identity/branding-guidelines --> +<#macro kw name="Google"> + + ${name} + + + + + + diff --git a/theme/keywind/login/assets/providers/instagram.ftl b/theme/keywind/login/assets/providers/instagram.ftl new file mode 100644 index 0000000..c4996d8 --- /dev/null +++ b/theme/keywind/login/assets/providers/instagram.ftl @@ -0,0 +1,35 @@ +<#-- https://www.facebook.com/brand/resources/instagram/instagram-brand --> +<#macro kw name="Instagram"> + + ${name} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/theme/keywind/login/assets/providers/linkedin.ftl b/theme/keywind/login/assets/providers/linkedin.ftl new file mode 100644 index 0000000..944d143 --- /dev/null +++ b/theme/keywind/login/assets/providers/linkedin.ftl @@ -0,0 +1,7 @@ +<#-- https://brand.linkedin.com/downloads --> +<#macro kw name="LinkedIn"> + + ${name} + + + diff --git a/theme/keywind/login/assets/providers/microsoft.ftl b/theme/keywind/login/assets/providers/microsoft.ftl new file mode 100644 index 0000000..408635b --- /dev/null +++ b/theme/keywind/login/assets/providers/microsoft.ftl @@ -0,0 +1,10 @@ +<#-- https://learn.microsoft.com/azure/active-directory/develop/howto-add-branding-in-azure-ad-apps --> +<#macro kw name="Microsoft"> + + ${name} + + + + + + diff --git a/theme/keywind/login/assets/providers/oidc.ftl b/theme/keywind/login/assets/providers/oidc.ftl new file mode 100644 index 0000000..f7954ff --- /dev/null +++ b/theme/keywind/login/assets/providers/oidc.ftl @@ -0,0 +1,9 @@ +<#-- https://openid.net/add-openid/logos --> +<#macro kw name="OpenID"> + + ${name} + + + + + diff --git a/theme/keywind/login/assets/providers/openshift.ftl b/theme/keywind/login/assets/providers/openshift.ftl new file mode 100644 index 0000000..e85ddef --- /dev/null +++ b/theme/keywind/login/assets/providers/openshift.ftl @@ -0,0 +1,11 @@ +<#-- https://www.redhat.com/technologies/cloud-computing/openshift --> +<#macro kw name="Red Hat OpenShift"> + + ${name} + + + + + + + diff --git a/theme/keywind/login/assets/providers/paypal.ftl b/theme/keywind/login/assets/providers/paypal.ftl new file mode 100644 index 0000000..7946e03 --- /dev/null +++ b/theme/keywind/login/assets/providers/paypal.ftl @@ -0,0 +1,9 @@ +<#-- https://www.paypal.com --> +<#macro kw name="PayPal"> + + ${name} + + + + + diff --git a/theme/keywind/login/assets/providers/providers.ftl b/theme/keywind/login/assets/providers/providers.ftl new file mode 100644 index 0000000..b2d943a --- /dev/null +++ b/theme/keywind/login/assets/providers/providers.ftl @@ -0,0 +1,84 @@ +<#import "./apple.ftl" as appleIcon> +<#import "./bitbucket.ftl" as bitbucketIcon> +<#import "./discord.ftl" as discordIcon> +<#import "./facebook.ftl" as facebookIcon> +<#import "./github.ftl" as githubIcon> +<#import "./gitlab.ftl" as gitlabIcon> +<#import "./google.ftl" as googleIcon> +<#import "./instagram.ftl" as instagramIcon> +<#import "./linkedin.ftl" as linkedinIcon> +<#import "./microsoft.ftl" as microsoftIcon> +<#import "./oidc.ftl" as oidcIcon> +<#import "./openshift.ftl" as openshiftIcon> +<#import "./paypal.ftl" as paypalIcon> +<#import "./slack.ftl" as slackIcon> +<#import "./stackoverflow.ftl" as stackoverflowIcon> +<#import "./twitter.ftl" as twitterIcon> + +<#macro apple> + <@appleIcon.kw /> + + +<#macro bitbucket> + <@bitbucketIcon.kw /> + + +<#macro discord> + <@discordIcon.kw /> + + +<#macro facebook> + <@facebookIcon.kw /> + + +<#macro github> + <@githubIcon.kw /> + + +<#macro gitlab> + <@gitlabIcon.kw /> + + +<#macro google> + <@googleIcon.kw /> + + +<#macro instagram> + <@instagramIcon.kw /> + + +<#macro "linkedin-openid-connect"> + <@linkedinIcon.kw /> + + +<#macro microsoft> + <@microsoftIcon.kw /> + + +<#macro oidc> + <@oidcIcon.kw /> + + +<#macro "openshift-v3"> + <@openshiftIcon.kw /> + + +<#macro "openshift-v4"> + <@openshiftIcon.kw /> + + +<#macro paypal> + <@paypalIcon.kw /> + + +<#macro slack> + <@slackIcon.kw /> + + +<#macro stackoverflow> + <@stackoverflowIcon.kw /> + + +<#macro twitter> + <@twitterIcon.kw /> + diff --git a/theme/keywind/login/assets/providers/slack.ftl b/theme/keywind/login/assets/providers/slack.ftl new file mode 100644 index 0000000..d4dffe3 --- /dev/null +++ b/theme/keywind/login/assets/providers/slack.ftl @@ -0,0 +1,14 @@ +<#-- https://slack.com/media-kit --> +<#macro kw name="Slack"> + + ${name} + + + + + + + + + + diff --git a/theme/keywind/login/assets/providers/stackoverflow.ftl b/theme/keywind/login/assets/providers/stackoverflow.ftl new file mode 100644 index 0000000..1ffad8d --- /dev/null +++ b/theme/keywind/login/assets/providers/stackoverflow.ftl @@ -0,0 +1,8 @@ +<#-- https://stackoverflow.design/brand/logo --> +<#macro kw name="Stack Overflow"> + + ${name} + + + + diff --git a/theme/keywind/login/assets/providers/twitter.ftl b/theme/keywind/login/assets/providers/twitter.ftl new file mode 100644 index 0000000..2bc7e7e --- /dev/null +++ b/theme/keywind/login/assets/providers/twitter.ftl @@ -0,0 +1,7 @@ +<#-- https://about.twitter.com/en/who-we-are/brand-toolkit --> +<#macro kw name="Twitter"> + + ${name} + + + diff --git a/theme/keywind/login/components/atoms/alert.ftl b/theme/keywind/login/components/atoms/alert.ftl new file mode 100644 index 0000000..58e8309 --- /dev/null +++ b/theme/keywind/login/components/atoms/alert.ftl @@ -0,0 +1,22 @@ +<#macro kw color=""> + <#switch color> + <#case "error"> + <#assign colorClass="bg-red-100 text-red-600"> + <#break> + <#case "info"> + <#assign colorClass="bg-blue-100 text-blue-600"> + <#break> + <#case "success"> + <#assign colorClass="bg-green-100 text-green-600"> + <#break> + <#case "warning"> + <#assign colorClass="bg-orange-100 text-orange-600"> + <#break> + <#default> + <#assign colorClass="bg-blue-100 text-blue-600"> + + + + diff --git a/theme/keywind/login/components/atoms/body.ftl b/theme/keywind/login/components/atoms/body.ftl new file mode 100644 index 0000000..dcc94a0 --- /dev/null +++ b/theme/keywind/login/components/atoms/body.ftl @@ -0,0 +1,5 @@ +<#macro kw> + + <#nested> + + diff --git a/theme/keywind/login/components/atoms/button-group.ftl b/theme/keywind/login/components/atoms/button-group.ftl new file mode 100644 index 0000000..4591209 --- /dev/null +++ b/theme/keywind/login/components/atoms/button-group.ftl @@ -0,0 +1,5 @@ +<#macro kw> +
+ <#nested> +
+ diff --git a/theme/keywind/login/components/atoms/button.ftl b/theme/keywind/login/components/atoms/button.ftl new file mode 100644 index 0000000..eeb0af7 --- /dev/null +++ b/theme/keywind/login/components/atoms/button.ftl @@ -0,0 +1,33 @@ +<#macro kw color="" component="button" size="" rest...> + <#switch color> + <#case "primary"> + <#assign colorClass="bg-primary-600 text-white focus:ring-primary-600 hover:bg-primary-700"> + <#break> + <#case "secondary"> + <#assign colorClass="bg-secondary-100 text-secondary-600 focus:ring-secondary-600 hover:bg-secondary-200 hover:text-secondary-900"> + <#break> + <#default> + <#assign colorClass="bg-primary-600 text-white focus:ring-primary-600 hover:bg-primary-700"> + + + <#switch size> + <#case "medium"> + <#assign sizeClass="px-4 py-2 text-sm"> + <#break> + <#case "small"> + <#assign sizeClass="px-2 py-1 text-xs"> + <#break> + <#default> + <#assign sizeClass="px-4 py-2 text-sm"> + + + <${component} + class="${colorClass} ${sizeClass} flex justify-center relative rounded-lg w-full focus:outline-none focus:ring-2 focus:ring-offset-2" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + <#nested> + + diff --git a/theme/keywind/login/components/atoms/card.ftl b/theme/keywind/login/components/atoms/card.ftl new file mode 100644 index 0000000..c1e808d --- /dev/null +++ b/theme/keywind/login/components/atoms/card.ftl @@ -0,0 +1,19 @@ +<#macro kw content="" footer="" header=""> +
+ <#if header?has_content> +
+ ${header} +
+ + <#if content?has_content> +
+ ${content} +
+ + <#if footer?has_content> +
+ ${footer} +
+ +
+ diff --git a/theme/keywind/login/components/atoms/checkbox.ftl b/theme/keywind/login/components/atoms/checkbox.ftl new file mode 100644 index 0000000..e47fd61 --- /dev/null +++ b/theme/keywind/login/components/atoms/checkbox.ftl @@ -0,0 +1,19 @@ +<#macro kw checked=false label="" name="" rest...> +
+ checked + + class="border-secondary-200 h-4 rounded text-primary-600 w-4 focus:ring-primary-200 focus:ring-opacity-50" + id="${name}" + name="${name}" + type="checkbox" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + +
+ diff --git a/theme/keywind/login/components/atoms/container.ftl b/theme/keywind/login/components/atoms/container.ftl new file mode 100644 index 0000000..34ead18 --- /dev/null +++ b/theme/keywind/login/components/atoms/container.ftl @@ -0,0 +1,5 @@ +<#macro kw> +
+ <#nested> +
+ diff --git a/theme/keywind/login/components/atoms/form.ftl b/theme/keywind/login/components/atoms/form.ftl new file mode 100644 index 0000000..014bb4f --- /dev/null +++ b/theme/keywind/login/components/atoms/form.ftl @@ -0,0 +1,11 @@ +<#macro kw rest...> +
+ ${attrName}="${attrValue}" + + > + <#nested> +
+ diff --git a/theme/keywind/login/components/atoms/heading.ftl b/theme/keywind/login/components/atoms/heading.ftl new file mode 100644 index 0000000..7665c01 --- /dev/null +++ b/theme/keywind/login/components/atoms/heading.ftl @@ -0,0 +1,5 @@ +<#macro kw> +

+ <#nested> +

+ diff --git a/theme/keywind/login/components/atoms/input.ftl b/theme/keywind/login/components/atoms/input.ftl new file mode 100644 index 0000000..714f832 --- /dev/null +++ b/theme/keywind/login/components/atoms/input.ftl @@ -0,0 +1,78 @@ +<#import "/assets/icons/eye.ftl" as iconEye> +<#import "/assets/icons/eye-slash.ftl" as iconEyeSlash> + +<#macro + kw + autofocus=false + class="block border-secondary-200 mt-1 rounded-md w-full focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 sm:text-sm" + disabled=false + invalid=false + label="" + message="" + name="" + required=true + type="text" + rest... +> +
+ + <#if type == "password"> +
+ autofocus + <#if disabled>disabled + <#if required>required + + aria-invalid="${invalid?c}" + class="${class}" + id="${name}" + name="${name}" + placeholder="${label}" + :type="show ? 'text' : 'password'" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + +
+ <#else> + autofocus + <#if disabled>disabled + <#if required>required + + aria-invalid="${invalid?c}" + class="${class}" + id="${name}" + name="${name}" + placeholder="${label}" + type="${type}" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + + <#if invalid?? && message??> +
+ ${message?no_esc} +
+ +
+ diff --git a/theme/keywind/login/components/atoms/link.ftl b/theme/keywind/login/components/atoms/link.ftl new file mode 100644 index 0000000..bde7666 --- /dev/null +++ b/theme/keywind/login/components/atoms/link.ftl @@ -0,0 +1,30 @@ +<#macro kw color="" component="a" size="" rest...> + <#switch color> + <#case "primary"> + <#assign colorClass="text-primary-600 hover:text-primary-500"> + <#break> + <#case "secondary"> + <#assign colorClass="text-secondary-600 hover:text-secondary-900"> + <#break> + <#default> + <#assign colorClass="text-primary-600 hover:text-primary-500"> + + + <#switch size> + <#case "small"> + <#assign sizeClass="text-sm"> + <#break> + <#default> + <#assign sizeClass=""> + + + <${component} + class="<#compress>${colorClass} ${sizeClass} inline-flex" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + <#nested> + + diff --git a/theme/keywind/login/components/atoms/logo.ftl b/theme/keywind/login/components/atoms/logo.ftl new file mode 100644 index 0000000..e883322 --- /dev/null +++ b/theme/keywind/login/components/atoms/logo.ftl @@ -0,0 +1,8 @@ +<#macro kw> +
+ diff --git a/theme/keywind/login/components/atoms/nav.ftl b/theme/keywind/login/components/atoms/nav.ftl new file mode 100644 index 0000000..81a4abf --- /dev/null +++ b/theme/keywind/login/components/atoms/nav.ftl @@ -0,0 +1,5 @@ +<#macro kw> +
+ <#nested> +
+ diff --git a/theme/keywind/login/components/atoms/radio.ftl b/theme/keywind/login/components/atoms/radio.ftl new file mode 100644 index 0000000..5596d5c --- /dev/null +++ b/theme/keywind/login/components/atoms/radio.ftl @@ -0,0 +1,18 @@ +<#macro kw checked=false id="" label="" rest...> +
+ checked + + class="border-secondary-200 focus:ring-primary-600" + id="${id}" + type="radio" + + <#list rest as attrName, attrValue> + ${attrName}="${attrValue}" + + > + +
+ diff --git a/theme/keywind/login/components/molecules/identity-provider.ftl b/theme/keywind/login/components/molecules/identity-provider.ftl new file mode 100644 index 0000000..b59962e --- /dev/null +++ b/theme/keywind/login/components/molecules/identity-provider.ftl @@ -0,0 +1,81 @@ +<#import "/assets/providers/providers.ftl" as providerIcons> + +<#macro kw providers=[]> +
+ ${msg("identity-provider-login-label")} +
+
+ <#list providers as provider> + <#switch provider.alias> + <#case "apple"> + <#assign colorClass="hover:bg-provider-apple/10"> + <#break> + <#case "bitbucket"> + <#assign colorClass="hover:bg-provider-bitbucket/10"> + <#break> + <#case "discord"> + <#assign colorClass="hover:bg-provider-discord/10"> + <#break> + <#case "facebook"> + <#assign colorClass="hover:bg-provider-facebook/10"> + <#break> + <#case "github"> + <#assign colorClass="hover:bg-provider-github/10"> + <#break> + <#case "gitlab"> + <#assign colorClass="hover:bg-provider-gitlab/10"> + <#break> + <#case "google"> + <#assign colorClass="hover:bg-provider-google/10"> + <#break> + <#case "instagram"> + <#assign colorClass="hover:bg-provider-instagram/10"> + <#break> + <#case "linkedin-openid-connect"> + <#assign colorClass="hover:bg-provider-linkedin/10"> + <#break> + <#case "microsoft"> + <#assign colorClass="hover:bg-provider-microsoft/10"> + <#break> + <#case "oidc"> + <#assign colorClass="hover:bg-provider-oidc/10"> + <#break> + <#case "openshift-v3"> + <#assign colorClass="hover:bg-provider-openshift/10"> + <#break> + <#case "openshift-v4"> + <#assign colorClass="hover:bg-provider-openshift/10"> + <#break> + <#case "paypal"> + <#assign colorClass="hover:bg-provider-paypal/10"> + <#break> + <#case "slack"> + <#assign colorClass="hover:bg-provider-slack/10"> + <#break> + <#case "stackoverflow"> + <#assign colorClass="hover:bg-provider-stackoverflow/10"> + <#break> + <#case "twitter"> + <#assign colorClass="hover:bg-provider-twitter/10"> + <#break> + <#default> + <#assign colorClass="hover:bg-secondary-100"> + + + + <#if providerIcons[provider.alias]??> +
+ <@providerIcons[provider.alias] /> +
+ <#else> + ${provider.displayName!} + +
+ +
+ diff --git a/theme/keywind/login/components/molecules/locale-provider.ftl b/theme/keywind/login/components/molecules/locale-provider.ftl new file mode 100644 index 0000000..198e5be --- /dev/null +++ b/theme/keywind/login/components/molecules/locale-provider.ftl @@ -0,0 +1,29 @@ +<#import "/assets/icons/chevron-down.ftl" as icon> +<#import "/components/atoms/link.ftl" as link> + +<#macro kw currentLocale="" locales=[]> +
+ <@link.kw @click="open = true" color="secondary" component="button" type="button"> +
+ ${currentLocale} + <@icon.kw /> +
+ +
+ <#list locales as locale> + <#if currentLocale != locale.label> +
+ <@link.kw color="secondary" href=locale.url size="small"> + ${locale.label} + +
+ + +
+
+ diff --git a/theme/keywind/login/components/molecules/username.ftl b/theme/keywind/login/components/molecules/username.ftl new file mode 100644 index 0000000..ba63393 --- /dev/null +++ b/theme/keywind/login/components/molecules/username.ftl @@ -0,0 +1,15 @@ +<#import "/assets/icons/arrow-top-right-on-square.ftl" as icon> +<#import "/components/atoms/link.ftl" as link> + +<#macro kw linkHref="" linkTitle="" name=""> +
+ ${name} + <@link.kw + color="primary" + href=linkHref + title=linkTitle + > + <@icon.kw /> + +
+ diff --git a/theme/keywind/login/document.ftl b/theme/keywind/login/document.ftl new file mode 100644 index 0000000..188e16a --- /dev/null +++ b/theme/keywind/login/document.ftl @@ -0,0 +1,35 @@ +<#macro kw script=""> + ${msg("loginTitle", (realm.displayName!""))} + + + + + + <#if properties.meta?has_content> + <#list properties.meta?split(" ") as meta> + + + + + <#if properties.favicons?has_content> + <#list properties.favicons?split(" ") as favicon> + + + + + <#if properties.styles?has_content> + <#list properties.styles?split(" ") as style> + + + + + <#if script?has_content> + + + + <#if properties.scripts?has_content> + <#list properties.scripts?split(" ") as script> + + + + diff --git a/theme/keywind/login/error.ftl b/theme/keywind/login/error.ftl new file mode 100644 index 0000000..52af9c1 --- /dev/null +++ b/theme/keywind/login/error.ftl @@ -0,0 +1,18 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/alert.ftl" as alert> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout displayMessage=false; section> + <#if section="header"> + ${kcSanitize(msg("errorTitle"))?no_esc} + <#elseif section="form"> + <@alert.kw color="error">${kcSanitize(message.summary)?no_esc} + <#if !skipLink??> + <#if client?? && client.baseUrl?has_content> + <@link.kw color="secondary" href=client.baseUrl size="small"> + ${kcSanitize(msg("backToApplication"))?no_esc} + + + + + diff --git a/theme/keywind/login/features/labels/totp-device.ftl b/theme/keywind/login/features/labels/totp-device.ftl new file mode 100644 index 0000000..98ae12f --- /dev/null +++ b/theme/keywind/login/features/labels/totp-device.ftl @@ -0,0 +1,5 @@ +<#macro kw> + <#compress> + ${msg("loginTotpDeviceName")} <#if totp.otpCredentials?size gte 1>* + + diff --git a/theme/keywind/login/features/labels/totp.ftl b/theme/keywind/login/features/labels/totp.ftl new file mode 100644 index 0000000..be5158e --- /dev/null +++ b/theme/keywind/login/features/labels/totp.ftl @@ -0,0 +1,5 @@ +<#macro kw> + <#compress> + ${msg("authenticatorCode")} * + + diff --git a/theme/keywind/login/features/labels/username.ftl b/theme/keywind/login/features/labels/username.ftl new file mode 100644 index 0000000..6c01d6b --- /dev/null +++ b/theme/keywind/login/features/labels/username.ftl @@ -0,0 +1,11 @@ +<#macro kw> + <#compress> + <#if !realm.loginWithEmailAllowed> + ${msg("username")} + <#elseif !realm.registrationEmailAsUsername> + ${msg("usernameOrEmail")} + <#else> + ${msg("email")} + + + diff --git a/theme/keywind/login/login-config-totp.ftl b/theme/keywind/login/login-config-totp.ftl new file mode 100644 index 0000000..e0b64c6 --- /dev/null +++ b/theme/keywind/login/login-config-totp.ftl @@ -0,0 +1,110 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "features/labels/totp.ftl" as totpLabel> +<#import "features/labels/totp-device.ftl" as totpDeviceLabel> + +<#assign totpLabel><@totpLabel.kw /> +<#assign totpDeviceLabel><@totpDeviceLabel.kw /> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("totp", "userLabel") + displayRequiredFields=false + ; + section +> + <#if section="header"> + ${msg("loginTotpTitle")} + <#elseif section="form"> +
    +
  1. +

    ${msg("loginTotpStep1")}

    +
      + <#list totp.supportedApplications as app> +
    • ${msg(app)}
    • + +
    +
  2. + <#if mode?? && mode="manual"> +
  3. +

    ${msg("loginTotpManualStep2")}

    +

    ${totp.totpSecretEncoded}

    +
  4. +
  5. + <@link.kw color="primary" href=totp.qrUrl> + ${msg("loginTotpScanBarcode")} + +
  6. +
  7. +

    ${msg("loginTotpManualStep3")}

    +
      +
    • ${msg("loginTotpType")}: ${msg("loginTotp." + totp.policy.type)}
    • +
    • ${msg("loginTotpAlgorithm")}: ${totp.policy.getAlgorithmKey()}
    • +
    • ${msg("loginTotpDigits")}: ${totp.policy.digits}
    • + <#if totp.policy.type="totp"> +
    • ${msg("loginTotpInterval")}: ${totp.policy.period}
    • + <#elseif totp.policy.type="hotp"> +
    • ${msg("loginTotpCounter")}: ${totp.policy.initialCounter}
    • + +
    +
  8. + <#else> +
  9. +

    ${msg("loginTotpStep2")}

    + Figure: Barcode + <@link.kw color="primary" href=totp.manualUrl> + ${msg("loginTotpUnableToScan")} + +
  10. + +
  11. ${msg("loginTotpStep3")}
  12. +
  13. ${msg("loginTotpStep3DeviceName")}
  14. +
+ <@form.kw action=url.loginAction method="post"> + + <#if mode??> + + + <@input.kw + autocomplete="off" + autofocus=true + invalid=messagesPerField.existsError("totp") + label=totpLabel + message=kcSanitize(messagesPerField.get("totp")) + name="totp" + required=false + type="text" + /> + <@input.kw + autocomplete="off" + invalid=messagesPerField.existsError("userLabel") + label=totpDeviceLabel + message=kcSanitize(messagesPerField.get("userLabel")) + name="userLabel" + required=false + type="text" + /> + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + + + diff --git a/theme/keywind/login/login-idp-link-confirm.ftl b/theme/keywind/login/login-idp-link-confirm.ftl new file mode 100644 index 0000000..9a2554d --- /dev/null +++ b/theme/keywind/login/login-idp-link-confirm.ftl @@ -0,0 +1,18 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/form.ftl" as form> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("confirmLinkIdpTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <@button.kw color="primary" name="submitAction" type="submit" value="updateProfile"> + ${msg("confirmLinkIdpReviewProfile")} + + <@button.kw color="primary" name="submitAction" type="submit" value="linkAccount"> + ${msg("confirmLinkIdpContinue", idpDisplayName)} + + + + diff --git a/theme/keywind/login/login-oauth-grant.ftl b/theme/keywind/login/login-oauth-grant.ftl new file mode 100644 index 0000000..aa4173c --- /dev/null +++ b/theme/keywind/login/login-oauth-grant.ftl @@ -0,0 +1,62 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> + +<@layout.registrationLayout; section> + <#if section="header"> + <#if client.attributes.logoUri??> + + +

+ <#if client.name?has_content> + ${msg("oauthGrantTitle", advancedMsg(client.name))} + <#else> + ${msg("oauthGrantTitle", client.clientId)} + +

+ <#elseif section="form"> +

${msg("oauthGrantRequest")}

+
    + <#if oauth.clientScopesRequested??> + <#list oauth.clientScopesRequested as clientScope> +
  • + <#if !clientScope.dynamicScopeParameter??> + ${advancedMsg(clientScope.consentScreenText)} + <#else> + ${advancedMsg(clientScope.consentScreenText)}: ${clientScope.dynamicScopeParameter} + +
  • + + +
+ <#if client.attributes.policyUri?? || client.attributes.tosUri??> +

+ <#if client.name?has_content> + ${msg("oauthGrantInformation",advancedMsg(client.name))} + <#else> + ${msg("oauthGrantInformation",client.clientId)} + + <#if client.attributes.tosUri??> + ${msg("oauthGrantReview")} + ${msg("oauthGrantTos")} + + <#if client.attributes.policyUri??> + ${msg("oauthGrantReview")} + ${msg("oauthGrantPolicy")} + +

+ + <@form.kw action=url.oauthAction method="post"> + + <@buttonGroup.kw> + <@button.kw color="primary" name="accept" type="submit"> + ${msg("doYes")} + + <@button.kw color="secondary" name="cancel" type="submit"> + ${msg("doNo")} + + + + + diff --git a/theme/keywind/login/login-otp.ftl b/theme/keywind/login/login-otp.ftl new file mode 100644 index 0000000..b1bb3b9 --- /dev/null +++ b/theme/keywind/login/login-otp.ftl @@ -0,0 +1,50 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/radio.ftl" as radio> +<#import "features/labels/totp.ftl" as totpLabel> + +<#assign totpLabel><@totpLabel.kw /> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("totp") + ; + section +> + <#if section="header"> + ${msg("doLogIn")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <#if otpLogin.userOtpCredentials?size gt 1> +
+ <#list otpLogin.userOtpCredentials as otpCredential> + <@radio.kw + checked=(otpCredential.id == otpLogin.selectedCredentialId) + id="kw-otp-credential-${otpCredential?index}" + label=otpCredential.userLabel + name="selectedCredentialId" + tabindex=otpCredential?index + value=otpCredential.id + /> + +
+ + <@input.kw + autocomplete="off" + autofocus=true + invalid=messagesPerField.existsError("totp") + label=totpLabel + message=kcSanitize(messagesPerField.get("totp")) + name="otp" + type="text" + /> + <@buttonGroup.kw> + <@button.kw color="primary" name="submitAction" type="submit"> + ${msg("doLogIn")} + + + + + diff --git a/theme/keywind/login/login-page-expired.ftl b/theme/keywind/login/login-page-expired.ftl new file mode 100644 index 0000000..2b6288d --- /dev/null +++ b/theme/keywind/login/login-page-expired.ftl @@ -0,0 +1,18 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("pageExpiredTitle")} + <#elseif section="form"> + <@buttonGroup.kw> + <@button.kw color="primary" component="a" href=url.loginRestartFlowUrl> + ${msg("doTryAgain")} + + <@button.kw color="secondary" component="a" href=url.loginAction> + ${msg("doContinue")} + + + + diff --git a/theme/keywind/login/login-password.ftl b/theme/keywind/login/login-password.ftl new file mode 100644 index 0000000..54e7d9d --- /dev/null +++ b/theme/keywind/login/login-password.ftl @@ -0,0 +1,39 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout displayMessage=!messagesPerField.existsError("password"); section> + <#if section="header"> + ${msg("doLogIn")} + <#elseif section="form"> + <@form.kw + action=url.loginAction + method="post" + onsubmit="login.disabled = true; return true;" + > + <@input.kw + autofocus=true + invalid=messagesPerField.existsError("password") + label=msg("password") + message=kcSanitize(messagesPerField.get("password"))?no_esc + name="password" + type="password" + /> + <#if realm.resetPasswordAllowed> +
+ <@link.kw color="primary" href=url.loginResetCredentialsUrl size="small"> + ${msg("doForgotPassword")} + +
+ + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + diff --git a/theme/keywind/login/login-recovery-authn-code-config.ftl b/theme/keywind/login/login-recovery-authn-code-config.ftl new file mode 100644 index 0000000..186d710 --- /dev/null +++ b/theme/keywind/login/login-recovery-authn-code-config.ftl @@ -0,0 +1,91 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/alert.ftl" as alert> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> + +<@layout.registrationLayout script="dist/recoveryCodes.js"; section> + <#if section="header"> + ${msg("recovery-code-config-header")} + <#elseif section="form"> +
+ <@alert.kw color="warning"> +
+

${msg("recovery-code-config-warning-title")}

+

${msg("recovery-code-config-warning-message")}

+
+ +
    + <#list recoveryAuthnCodesConfigBean.generatedRecoveryAuthnCodesList as code> +
  • ${code[0..3]}-${code[4..7]}-${code[8..]}
  • + +
+
+ <@button.kw @click="print" color="secondary" size="small" type="button"> + ${msg("recovery-codes-print")} + + <@button.kw @click="download" color="secondary" size="small" type="button"> + ${msg("recovery-codes-download")} + + <@button.kw @click="copy" color="secondary" size="small" type="button"> + ${msg("recovery-codes-copy")} + +
+ <@form.kw action=url.loginAction method="post"> + + + + <@checkbox.kw + label=msg("recovery-codes-confirmation-message") + name="kcRecoveryCodesConfirmationCheck" + required="required" + x\-ref="confirmationCheck" + /> + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("recovery-codes-action-complete")} + + <@button.kw + @click="$refs.confirmationCheck.required = false" + color="secondary" + name="cancel-aia" + type="submit" + value="true" + > + ${msg("recovery-codes-action-cancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("recovery-codes-action-complete")} + + + + +
+ + + + diff --git a/theme/keywind/login/login-recovery-authn-code-input.ftl b/theme/keywind/login/login-recovery-authn-code-input.ftl new file mode 100644 index 0000000..a46bcfa --- /dev/null +++ b/theme/keywind/login/login-recovery-authn-code-input.ftl @@ -0,0 +1,26 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("auth-recovery-code-header")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <@input.kw + autocomplete="off" + autofocus=true + label=msg("auth-recovery-code-prompt", recoveryAuthnCodesInputBean.codeNumber?c) + name="recoveryCodeInput" + type="text" + /> + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + diff --git a/theme/keywind/login/login-reset-password.ftl b/theme/keywind/login/login-reset-password.ftl new file mode 100644 index 0000000..9c95003 --- /dev/null +++ b/theme/keywind/login/login-reset-password.ftl @@ -0,0 +1,48 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "features/labels/username.ftl" as usernameLabel> + +<#assign usernameLabel><@usernameLabel.kw /> + +<@layout.registrationLayout + displayInfo=true + displayMessage=!messagesPerField.existsError("username") + ; + section +> + <#if section="header"> + ${msg("emailForgotTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <@input.kw + autocomplete=realm.loginWithEmailAllowed?string("email", "username") + autofocus=true + invalid=messagesPerField.existsError("username") + label=usernameLabel + message=kcSanitize(messagesPerField.get("username")) + name="username" + type="text" + value=(auth?has_content && auth.showUsername())?then(auth.attemptedUsername, '') + /> + <@buttonGroup.kw> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + <#elseif section="info"> + <#if realm.loginWithEmailAllowed> + ${msg("emailInstruction")} + <#else> + ${msg("emailInstructionUsername")} + + <#elseif section="nav"> + <@link.kw color="secondary" href=url.loginUrl size="small"> + ${kcSanitize(msg("backToLogin"))?no_esc} + + + diff --git a/theme/keywind/login/login-update-password.ftl b/theme/keywind/login/login-update-password.ftl new file mode 100644 index 0000000..ed82380 --- /dev/null +++ b/theme/keywind/login/login-update-password.ftl @@ -0,0 +1,64 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("password", "password-confirm") + ; + section +> + <#if section="header"> + ${msg("updatePasswordTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + + + <@input.kw + autocomplete="new-password" + autofocus=true + invalid=messagesPerField.existsError("password", "password-confirm") + label=msg("passwordNew") + name="password-new" + type="password" + /> + <@input.kw + autocomplete="new-password" + invalid=messagesPerField.existsError("password-confirm") + label=msg("passwordConfirm") + message=kcSanitize(messagesPerField.get("password-confirm")) + name="password-confirm" + type="password" + /> + <#if isAppInitiatedAction??> + <@checkbox.kw + checked=true + label=msg("logoutOtherSessions") + name="logout-sessions" + value="on" + /> + + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + + + diff --git a/theme/keywind/login/login-update-profile.ftl b/theme/keywind/login/login-update-profile.ftl new file mode 100644 index 0000000..306bad9 --- /dev/null +++ b/theme/keywind/login/login-update-profile.ftl @@ -0,0 +1,71 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("email", "firstName", "lastName", "username") + ; + section +> + <#if section="header"> + ${msg("loginProfileTitle")} + <#elseif section="form"> + <@form.kw action=url.loginAction method="post"> + <#if user.editUsernameAllowed> + <@input.kw + autocomplete="username" + autofocus=true + invalid=messagesPerField.existsError("username") + label=msg("username") + message=kcSanitize(messagesPerField.get("username")) + name="username" + type="text" + value=(user.username)!'' + /> + + <@input.kw + autocomplete="email" + invalid=messagesPerField.existsError("email") + label=msg("email") + message=kcSanitize(messagesPerField.get("email")) + name="email" + type="email" + value=(user.email)!'' + /> + <@input.kw + autocomplete="given-name" + invalid=messagesPerField.existsError("firstName") + label=msg("firstName") + message=kcSanitize(messagesPerField.get("firstName")) + name="firstName" + type="text" + value=(user.firstName)!'' + /> + <@input.kw + autocomplete="family-name" + invalid=messagesPerField.existsError("lastName") + label=msg("lastName") + message=kcSanitize(messagesPerField.get("lastName")) + name="lastName" + type="text" + value=(user.lastName)!'' + /> + <@buttonGroup.kw> + <#if isAppInitiatedAction??> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + + <#else> + <@button.kw color="primary" type="submit"> + ${msg("doSubmit")} + + + + + + diff --git a/theme/keywind/login/login-username.ftl b/theme/keywind/login/login-username.ftl new file mode 100644 index 0000000..b8064b2 --- /dev/null +++ b/theme/keywind/login/login-username.ftl @@ -0,0 +1,71 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "components/molecules/identity-provider.ftl" as identityProvider> +<#import "features/labels/username.ftl" as usernameLabel> + +<#assign usernameLabel><@usernameLabel.kw /> + +<@layout.registrationLayout + displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled?? + displayMessage=!messagesPerField.existsError("username") + ; + section +> + <#if section="header"> + ${msg("loginAccountTitle")} + <#elseif section="form"> + <#if realm.password> + <@form.kw + action=url.loginAction + method="post" + onsubmit="login.disabled = true; return true;" + > + <#if !usernameHidden??> + <@input.kw + autocomplete=realm.loginWithEmailAllowed?string("email", "username") + autofocus=true + disabled=usernameEditDisabled?? + invalid=messagesPerField.existsError("username") + label=usernameLabel + message=kcSanitize(messagesPerField.get("username"))?no_esc + name="username" + type="text" + value=(login.username)!'' + /> + + <#if realm.rememberMe && !usernameHidden??> +
+ <@checkbox.kw + checked=login.rememberMe?? + label=msg("rememberMe") + name="rememberMe" + /> +
+ + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + <#elseif section="info"> + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> +
+ ${msg("noAccount")} + <@link.kw color="primary" href=url.registrationUrl> + ${msg("doRegister")} + +
+ + <#elseif section="socialProviders"> + <#if realm.password && social.providers??> + <@identityProvider.kw providers=social.providers /> + + + diff --git a/theme/keywind/login/login-x509-info.ftl b/theme/keywind/login/login-x509-info.ftl new file mode 100644 index 0000000..70d8432 --- /dev/null +++ b/theme/keywind/login/login-x509-info.ftl @@ -0,0 +1,40 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout; section> + <#if section = "header"> + ${msg("doLogIn")} + <#elseif section = "form"> +
+
${msg("clientCertificate")}
+
+ <#if x509.formData.subjectDN??> + ${(x509.formData.subjectDN!"")} + <#else> + ${msg("noCertificate")} + +
+
+ <#if x509.formData.isUserEnabled??> +
+ ${msg("doX509Login")} + ${(x509.formData.username!'')} +
+ + <@form.kw action=url.loginAction method="post"> + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doContinue")} + + <#if x509.formData.isUserEnabled??> + <@button.kw color="secondary" name="cancel" type="submit"> + ${msg("doIgnore")} + + + + + + diff --git a/theme/keywind/login/login.ftl b/theme/keywind/login/login.ftl new file mode 100644 index 0000000..331da06 --- /dev/null +++ b/theme/keywind/login/login.ftl @@ -0,0 +1,87 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/checkbox.ftl" as checkbox> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> +<#import "components/molecules/identity-provider.ftl" as identityProvider> +<#import "features/labels/username.ftl" as usernameLabel> + +<#assign usernameLabel><@usernameLabel.kw /> + +<@layout.registrationLayout + displayInfo=realm.password && realm.registrationAllowed && !registrationDisabled?? + displayMessage=!messagesPerField.existsError("username", "password") + ; + section +> + <#if section="header"> + ${msg("loginAccountTitle")} + <#elseif section="form"> + <#if realm.password> + <@form.kw + action=url.loginAction + method="post" + onsubmit="login.disabled = true; return true;" + > + + <@input.kw + autocomplete=realm.loginWithEmailAllowed?string("email", "username") + autofocus=true + disabled=usernameEditDisabled?? + invalid=messagesPerField.existsError("username", "password") + label=usernameLabel + message=kcSanitize(messagesPerField.getFirstError("username", "password")) + name="username" + type="text" + value=(login.username)!'' + /> + <@input.kw + invalid=messagesPerField.existsError("username", "password") + label=msg("password") + name="password" + type="password" + /> + <#if realm.rememberMe && !usernameEditDisabled?? || realm.resetPasswordAllowed> +
+ <#if realm.rememberMe && !usernameEditDisabled??> + <@checkbox.kw + checked=login.rememberMe?? + label=msg("rememberMe") + name="rememberMe" + /> + + <#if realm.resetPasswordAllowed> + <@link.kw color="primary" href=url.loginResetCredentialsUrl size="small"> + ${msg("doForgotPassword")} + + +
+ + <@buttonGroup.kw> + <@button.kw color="primary" name="login" type="submit"> + ${msg("doLogIn")} + + + + + <#elseif section="info"> + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> +
+ ${msg("noAccount")} + <@link.kw color="primary" href=url.registrationUrl> + ${msg("doRegister")} + +
+ + <#elseif section="socialProviders"> + <#if realm.password && social.providers??> + <@identityProvider.kw providers=social.providers /> + + + diff --git a/theme/keywind/login/logout-confirm.ftl b/theme/keywind/login/logout-confirm.ftl new file mode 100644 index 0000000..e7ec486 --- /dev/null +++ b/theme/keywind/login/logout-confirm.ftl @@ -0,0 +1,25 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout; section> + <#if section="header"> + ${msg("logoutConfirmTitle")} + <#elseif section="form"> +

${msg("logoutConfirmHeader")}

+ <@form.kw action=url.logoutConfirmAction method="post"> + + <@button.kw color="primary" name="confirmLogout" type="submit" value=msg('doLogout')> + ${msg("doLogout")} + + + <#if !logoutConfirm.skipLink> + <#if (client.baseUrl)?has_content> + <@link.kw color="secondary" href=client.baseUrl size="small"> + ${kcSanitize(msg("backToApplication"))?no_esc} + + + + + diff --git a/theme/keywind/login/register.ftl b/theme/keywind/login/register.ftl new file mode 100644 index 0000000..c1a2f06 --- /dev/null +++ b/theme/keywind/login/register.ftl @@ -0,0 +1,88 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/input.ftl" as input> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout + displayMessage=!messagesPerField.existsError("firstName", "lastName", "email", "username", "password", "password-confirm") + ; + section +> + <#if section="header"> + ${msg("registerTitle")} + <#elseif section="form"> + <@form.kw action=url.registrationAction method="post"> + <@input.kw + autocomplete="given-name" + autofocus=true + invalid=messagesPerField.existsError("firstName") + label=msg("firstName") + message=kcSanitize(messagesPerField.get("firstName")) + name="firstName" + type="text" + value=(register.formData.firstName)!'' + /> + <@input.kw + autocomplete="family-name" + invalid=messagesPerField.existsError("lastName") + label=msg("lastName") + message=kcSanitize(messagesPerField.get("lastName")) + name="lastName" + type="text" + value=(register.formData.lastName)!'' + /> + <@input.kw + autocomplete="email" + invalid=messagesPerField.existsError("email") + label=msg("email") + message=kcSanitize(messagesPerField.get("email")) + name="email" + type="email" + value=(register.formData.email)!'' + /> + <#if !realm.registrationEmailAsUsername> + <@input.kw + autocomplete="username" + invalid=messagesPerField.existsError("username") + label=msg("username") + message=kcSanitize(messagesPerField.get("username")) + name="username" + type="text" + value=(register.formData.username)!'' + /> + + <#if passwordRequired??> + <@input.kw + autocomplete="new-password" + invalid=messagesPerField.existsError("password", "password-confirm") + label=msg("password") + message=kcSanitize(messagesPerField.getFirstError("password", "password-confirm")) + name="password" + type="password" + /> + <@input.kw + autocomplete="new-password" + invalid=messagesPerField.existsError("password-confirm") + label=msg("passwordConfirm") + message=kcSanitize(messagesPerField.get("password-confirm")) + name="password-confirm" + type="password" + /> + + <#if recaptchaRequired??> +
+ + <@buttonGroup.kw> + <@button.kw color="primary" type="submit"> + ${msg("doRegister")} + + + + <#elseif section="nav"> + <@link.kw color="secondary" href=url.loginUrl size="small"> + ${kcSanitize(msg("backToLogin"))?no_esc} + + + diff --git a/theme/keywind/login/resources/header-logo.png b/theme/keywind/login/resources/header-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aba90715c1f99426efdde30d71c5b3d30673a8cf GIT binary patch literal 16932 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 literal 0 HcmV?d00001 diff --git a/theme/keywind/login/select-authenticator.ftl b/theme/keywind/login/select-authenticator.ftl new file mode 100644 index 0000000..26a25fe --- /dev/null +++ b/theme/keywind/login/select-authenticator.ftl @@ -0,0 +1,28 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/form.ftl" as form> +<#import "components/atoms/link.ftl" as link> + +<@layout.registrationLayout displayInfo=false; section> + <#if section="header"> + ${msg("loginChooseAuthenticator")} + <#elseif section="form"> +
+ <@form.kw action=url.loginAction method="post" x\-ref="selectCredentialForm"> + + <#list auth.authenticationSelections as authenticationSelection> +
+ <@link.kw + @click="$refs.authExecInput.value = '${authenticationSelection.authExecId}'; $refs.selectCredentialForm.submit()" + color="primary" + component="button" + type="button" + > + ${msg("${authenticationSelection.displayName}")} + +
${msg("${authenticationSelection.helpText}")}
+
+ + +
+ + diff --git a/theme/keywind/login/template.ftl b/theme/keywind/login/template.ftl new file mode 100644 index 0000000..ddb0035 --- /dev/null +++ b/theme/keywind/login/template.ftl @@ -0,0 +1,84 @@ +<#import "document.ftl" as document> +<#import "components/atoms/alert.ftl" as alert> +<#import "components/atoms/body.ftl" as body> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/card.ftl" as card> +<#import "components/atoms/container.ftl" as container> +<#import "components/atoms/heading.ftl" as heading> +<#import "components/atoms/logo.ftl" as logo> +<#import "components/atoms/nav.ftl" as nav> +<#import "components/molecules/locale-provider.ftl" as localeProvider> +<#import "components/molecules/username.ftl" as username> + +<#macro + registrationLayout + displayInfo=false + displayMessage=true + displayRequiredFields=false + script="" + showAnotherWayIfPresent=true +> + <#assign cardHeader> + <@logo.kw> + ${kcSanitize(msg("loginTitleHtml", (realm.displayNameHtml!"")))?no_esc} + + <#if !(auth?has_content && auth.showUsername() && !auth.showResetCredentials())> + <@heading.kw> + <#nested "header"> + + <#else> + <#nested "show-username"> + <@username.kw + linkHref=url.loginRestartFlowUrl + linkTitle=msg("restartLoginTooltip") + name=auth.attemptedUsername + /> + + + + <#assign cardContent> + <#if displayMessage && message?has_content && (message.type != "warning" || !isAppInitiatedAction??)> + <@alert.kw color=message.type> + ${kcSanitize(message.summary)?no_esc} + + + <#nested "form"> + <#if displayRequiredFields> +

+ * ${msg("requiredFields")} +

+ + <#if auth?has_content && auth.showTryAnotherWayLink() && showAnotherWayIfPresent> +
+ + <@button.kw color="secondary" type="submit"> + ${msg("doTryAnotherWay")} + +
+ + <#nested "socialProviders"> + + + <#assign cardFooter> + <#if displayInfo> + <#nested "info"> + + + + lang="${locale.currentLanguageTag}"> + + <@document.kw script=script /> + + <@body.kw> + <@container.kw> + <@card.kw content=cardContent footer=cardFooter header=cardHeader /> + <@nav.kw> + <#nested "nav"> + <#if realm.internationalizationEnabled && locale.supported?size gt 1> + <@localeProvider.kw currentLocale=locale.current locales=locale.supported /> + + + + + + diff --git a/theme/keywind/login/terms.ftl b/theme/keywind/login/terms.ftl new file mode 100644 index 0000000..23386b8 --- /dev/null +++ b/theme/keywind/login/terms.ftl @@ -0,0 +1,22 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> +<#import "components/atoms/form.ftl" as form> + +<@layout.registrationLayout displayMessage=false; section> + <#if section="header"> + ${msg("termsTitle")} + <#elseif section="form"> + ${kcSanitize(msg("termsText"))?no_esc} + <@form.kw action=url.loginAction method="post"> + <@buttonGroup.kw> + <@button.kw color="primary" name="accept" type="submit"> + ${msg("doAccept")} + + <@button.kw color="secondary" name="cancel" type="submit"> + ${msg("doDecline")} + + + + + diff --git a/theme/keywind/login/theme.properties b/theme/keywind/login/theme.properties new file mode 100644 index 0000000..5e2a492 --- /dev/null +++ b/theme/keywind/login/theme.properties @@ -0,0 +1,4 @@ +parent=base + +styles=dist/index.css +scripts=dist/index.js diff --git a/theme/keywind/login/webauthn-authenticate.ftl b/theme/keywind/login/webauthn-authenticate.ftl new file mode 100644 index 0000000..189de50 --- /dev/null +++ b/theme/keywind/login/webauthn-authenticate.ftl @@ -0,0 +1,71 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> + +<@layout.registrationLayout script="dist/webAuthnAuthenticate.js"; section> + <#if section="title"> + title + <#elseif section="header"> + ${kcSanitize(msg("webauthn-login-title"))?no_esc} + <#elseif section="form"> +
+
+ + + + + + +
+ <#if authenticators??> +
+ <#list authenticators.authenticators as authenticator> + + +
+ <#if shouldDisplayAuthenticators?? && shouldDisplayAuthenticators> + <#if authenticators.authenticators?size gt 1> +

${kcSanitize(msg("webauthn-available-authenticators"))?no_esc}

+ + <#list authenticators.authenticators as authenticator> +
+
${kcSanitize(msg("${authenticator.label}"))?no_esc}
+ <#if authenticator.transports?? && authenticator.transports.displayNameProperties?has_content> +
+ <#list authenticator.transports.displayNameProperties as nameProperty> + ${kcSanitize(msg("${nameProperty!}"))?no_esc} + <#if nameProperty?has_next> + , + + +
+ +
+ ${kcSanitize(msg("webauthn-createdAt-label"))?no_esc} + ${kcSanitize(authenticator.createdAt)?no_esc} +
+
+ + + + <@buttonGroup.kw> + <@button.kw @click="webAuthnAuthenticate" color="primary" type="button"> + ${kcSanitize(msg("webauthn-doAuthenticate"))} + + +
+ + + + diff --git a/theme/keywind/login/webauthn-error.ftl b/theme/keywind/login/webauthn-error.ftl new file mode 100644 index 0000000..852d1e3 --- /dev/null +++ b/theme/keywind/login/webauthn-error.ftl @@ -0,0 +1,34 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> + +<@layout.registrationLayout displayMessage=true; section> + <#if section="header"> + ${kcSanitize(msg("webauthn-error-title"))?no_esc} + <#elseif section="form"> +
+
+ + +
+ <@buttonGroup.kw> + <@button.kw + @click="$refs.executionValueInput.value = '${execution}'; $refs.isSetRetryInput.value = 'retry'; $refs.errorCredentialForm.submit()" + color="primary" + name="try-again" + tabindex="4" + type="button" + > + ${kcSanitize(msg("doTryAgain"))?no_esc} + + <#if isAppInitiatedAction??> +
+ <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + +
+ + +
+ + diff --git a/theme/keywind/login/webauthn-register.ftl b/theme/keywind/login/webauthn-register.ftl new file mode 100644 index 0000000..57f4dad --- /dev/null +++ b/theme/keywind/login/webauthn-register.ftl @@ -0,0 +1,54 @@ +<#import "template.ftl" as layout> +<#import "components/atoms/button.ftl" as button> +<#import "components/atoms/button-group.ftl" as buttonGroup> + +<@layout.registrationLayout script="dist/webAuthnRegister.js"; section> + <#if section="title"> + title + <#elseif section="header"> + ${kcSanitize(msg("webauthn-registration-title"))?no_esc} + <#elseif section="form"> +
+
+ + + + + + +
+ <@buttonGroup.kw> + <@button.kw @click="registerSecurityKey" color="primary" type="submit"> + ${msg("doRegister")} + + <#if !isSetRetry?has_content && isAppInitiatedAction?has_content> +
+ <@button.kw color="secondary" name="cancel-aia" type="submit" value="true"> + ${msg("doCancel")} + +
+ + +
+ + + + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0e78c76 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "allowImportingTsExtensions": true, + "isolatedModules": true, + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..c134a6f --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "composite": true, + "module": "ESNext", + "moduleResolution": "bundler", + "skipLibCheck": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..3a18d54 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite'; + +export default defineConfig({ + build: { + rollupOptions: { + input: [ + 'src/index.ts', + 'src/data/recoveryCodes.ts', + 'src/data/webAuthnAuthenticate.ts', + 'src/data/webAuthnRegister.ts', + ], + output: { + assetFileNames: '[name][extname]', + dir: 'theme/keywind/login/resources/dist', + entryFileNames: '[name].js', + }, + }, + }, +});