st-login-form


Namest-login-form JSON
Version 1.2.0 PyPI version JSON
download
home_pagehttps://github.com/SiddhantSadangi/st_login_form
SummaryA streamlit component that creates a user login form connected to a Supabase DB. It lets users create a new username and password, login to an existing account, or login as an anonymous guest.
upload_time2024-11-03 13:56:25
maintainerNone
docs_urlNone
authorSiddhant Sadangi
requires_python>=3.8
licenseNone
keywords streamlit login
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <h1 align="center"> 🔐 Streamlit Login Form </h1>

<div align="center">
    <img src="https://img.shields.io/pypi/v/st-login-form.svg" alt="PyPI downloads">
    <a href="https://pepy.tech/project/st-login-form"> <img src="https://static.pepy.tech/personalized-badge/st-login-form?period=total&left_text=Downloads"> </a>
    <img src="https://img.shields.io/github/license/SiddhantSadangi/st_login_form.svg" alt="License">
    <img src="https://img.shields.io/badge/PRs-Welcome-brightgreen.svg" alt="PRs Welcome">
    <br><br>
    A Streamlit authentication component that creates a user login form connected to a Supabase DB.
    <br><br>
    <img src="assets/screenshot.png" alt="App screenshot">
</div>

## :balloon: Try the Demo App
<div align="center">
    <a href="https://st-lgn-form.streamlit.app/">
        <img src="https://static.streamlit.io/badges/streamlit_badge_black_white.svg" alt="Open in Streamlit" style="height: 60px !important;width: 217px !important;">
    </a>
</div>

## :rocket: Features
- One-line authentication frontend  
- Password hashing using the award-winning [Argon2](https://github.com/p-h-c/phc-winner-argon2) algorithm  
- Inbuilt password constraint checks
- Create new account, login to existing account, or login as guest
- Hash existing plaintext passwords in one-line of code
- Auto-collapses and disables the form on successful authentication

## :building_construction: Installation

1. Install `st-login-form`
```sh
pip install st-login-form
```
2. Create a Supabase project as mentioned [here](https://docs.streamlit.io/knowledge-base/tutorials/databases/supabase#sign-in-to-supabase-and-create-a-project)
3. Create a table to store the usernames and passwords. A sample DDL query is shown below:
  ```sql
  CREATE TABLE users (
      username text not null default ''::text,
      password text not null,
      constraint users_pkey primary key (username),
      constraint users_username_key unique (username),
      constraint users_password_check check (
        (
          length(
            trim(
              both
              from
                password
            )
          ) > 1
        )
      ),
      constraint users_username_check check (
        (
          length(
            trim(
              both
              from
                username
            )
          ) > 1
        )
      )
    ) tablespace pg_default;
  ```
4. Follow the rest of the steps from [here](https://docs.streamlit.io/knowledge-base/tutorials/databases/supabase#copy-your-app-secrets-to-the-cloud) to connect your Streamlit app to Supabase


## :pen: Usage

On authentication, `login_form()` sets the `st.session_state['authenticated']` to `True`. This also collapses and disables the login form.  
`st.session_state['username']` is set to the provided username for a new or existing user, and to `None` for guest login.

```python
import streamlit as st

from st_login_form import login_form

client = login_form()

if st.session_state["authenticated"]:
    if st.session_state["username"]:
        st.success(f"Welcome {st.session_state['username']}")
        ...

    else:
        st.success("Welcome guest")
        ...
else:
    st.error("Not authenticated")
```

### :key: Hashing existing plaintext passwords

Plaintext password for a user is automatically hashed during a login attempt.

To bulk-update all existing plaintext passwords in the table, use the `hash_current_passwords()` method.

### :bulb: API Reference

- `login_form()`

  ```python
    def login_form(
      *,
      title: str = "Authentication",
      icon: str = ":material/lock:",
      user_tablename: str = "users",
      username_col: str = "username",
      password_col: str = "password",
      constrain_password: bool = True,
      create_title: str = ":material/add_circle: Create new account",
      login_title: str = ":material/login: Login to existing account",
      allow_guest: bool = True,
      allow_create: bool = True,
      guest_title: str = ":material/visibility_off: Guest login",
      create_username_label: str = "Create a unique username",
      create_username_placeholder: str = None,
      create_username_help: str = None,
      create_password_label: str = "Create a password",
      create_password_placeholder: str = None,
      create_password_help: str = ":material/warning: Password cannot be recovered if lost",
      create_submit_label: str = ":material/add_circle: Create account",
      login_username_label: str = "Enter your unique username",
      login_username_placeholder: str = None,
      login_username_help: str = None,
      login_password_label: str = "Enter your password",
      login_password_placeholder: str = None,
      login_password_help: str = None,
      login_submit_label: str = ":material/login: Login",
      login_error_message: str = ":material/lock: Wrong username/password",
      password_constraint_check_fail_message: str = ":material/warning: Password must contain at least 8 characters, including one uppercase letter, one lowercase letter, one number, and one special character (`@$!%*?&_^#- `).",
      guest_submit_label: str = ":material/visibility_off: Guest login",
  ) -> Client:
      """Creates a user login form in Streamlit apps.

      Connects to a Supabase DB using `SUPABASE_URL` and `SUPABASE_KEY` Streamlit secrets.
      Sets `session_state["authenticated"]` to True if the login is successful.
      Sets `session_state["username"]` to provided username or new or existing user, and to `None` for guest login.

      Arguments:
          title (str): The title of the login form. Default is "Authentication".
          icon (str): The icon to display next to the title. Default is ":material/lock:".
          user_tablename (str): The name of the table in the database that stores user information. Default is "users".
          username_col (str): The name of the column in the user table that stores usernames. Default is "username".
          password_col (str): The name of the column in the user table that stores passwords. Default is "password".
          constrain_password (bool): Whether to enforce password constraints (at least 8 characters, including one uppercase letter, one lowercase letter, one number, and one special character (`@$!%*?&_^#- `)). Default is True.
          create_title (str): The title of the create new account tab. Default is ":material/add_circle: Create new account".
          login_title (str): The title of the login to existing account tab. Default is ":material/login: Login to existing account".
          allow_guest (bool): Whether to allow guest login. Default is True.
          allow_create (bool): Whether to allow creating new accounts. Default is True.
          guest_title (str): The title of the guest login tab. Default is ":material/visibility_off: Guest login".
          create_username_label (str): The label for the create username input field. Default is "Create a unique username".
          create_username_placeholder (str): The placeholder text for the create username input field. Default is None.
          create_username_help (str): The help text for the create username input field. Default is None.
          create_password_label (str): The label for the create password input field. Default is "Create a password".
          create_password_placeholder (str): The placeholder text for the create password input field. Default is None.
          create_password_help (str): The help text for the create password input field. Default is ":material/warning: Password cannot be recovered if lost".
          create_submit_label (str): The label for the create account submit button. Default is ":material/add_circle: Create account".
          login_username_label (str): The label for the login username input field. Default is "Enter your unique username".
          login_username_placeholder (str): The placeholder text for the login username input field. Default is None.
          login_username_help (str): The help text for the login username input field. Default is None.
          login_password_label (str): The label for the login password input field. Default is "Enter your password".
          login_password_placeholder (str): The placeholder text for the login password input field. Default is None.
          login_password_help (str): The help text for the login password input field. Default is None.
          login_submit_label (str): The label for the login submit button. Default is ":material/login: Login".
          login_error_message (str): The error message displayed when the username or password is incorrect. Default is ":material/lock: Wrong username/password".
          password_constraint_check_fail_message (str): The error message displayed when the password does not meet the constraints. Default is ":material/warning: Password must contain at least 8 characters, including one uppercase letter, one lowercase letter, one number, and one special character (`@$!%*?&_^#- `).".
          guest_submit_label (str): The label for the guest login button. Default is ":material/visibility_off: Guest login".

      Returns:
          Supabase.client: The client instance for performing downstream supabase operations.
      """
  ```

- `hash_current_passwords()`

  ```python
  def hash_current_passwords(
      user_tablename: str = "users",
      username_col: str = "username",
      password_col: str = "password",
  ) -> None:
      """Hashes all current plaintext passwords stored in a database table (in-place)."""
  ```

## :framed_picture: Gallery
Some notable Streamlit apps using `st-login-form`

- [SmartExam.io](https://smartexam.io/): SmartExam is an AI app that leverages University lectures to create interactive test exams.

_Want to feature your app? Create a PR!_

## :motorway:  Project Roadmap
Here are some features that are planned for future releases across the library and demo app. If you want to contribute to any of these features, feel free to open a PR!

### Library Features
- [ ] Add retype password for confirmation while signing up
- [ ] Customize password constraints (minimum length, allowed characters, etc.)
- [ ] Add logout option
- [ ] Capture additional login metadata - created_at, last_login_at, num_logins, etc.
- [ ] Add admin panel to set user roles and permissions
- [ ] Add password recovery option
- [ ] Support additional databases:
  - [ ] MySQL

### Demo App Features
- [ ] Allow users to customise demo login form  
- [ ] Add code preview for the rendered login form  

## :bow: Acknowledgements
- [Streamlit](https://streamlit.io) for the amazing Streamlit framework and promoting this library
- [Ahmed Ramadan](https://www.linkedin.com/in/theahmedrmdan/) for implementing password hashing
- Everyone who has shared feedback to improve this library!

## :handshake: Get Involved!
Your feedback and contributions can help shape the future of Streamlit Login Form. If you have ideas or features you'd like to see, let's collaborate!

- **Contribute**: Submit PRs or open issues on GitHub.
- **Connect**: Have questions or suggestions? Reach out to me on [LinkedIn](https://linkedin.com/in/siddhantsadangi) or [email](mailto:siddhant.sadangi@gmail.com).


## :sparkling_heart: Support Streamlit Login Form
Love Streamlit Login Form? Here's how you can show your support:

- **Star**: Give us a star on GitHub and help spread the word!
- **Share**: Tell your friends and colleagues about us on social media.
- **Donate**: Buy me a coffee and fuel further development!

<p align="center">
    <a href="https://www.buymeacoffee.com/siddhantsadangi" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;">
    </a>
</p>

Thank you for supporting Streamlit Login Form!

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/SiddhantSadangi/st_login_form",
    "name": "st-login-form",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "streamlit, login",
    "author": "Siddhant Sadangi",
    "author_email": "siddhant.sadangi@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/2c/97/6be7dd6f11c2a9614de575424cb4b1021e74368bd9fe44a2a7a761ce4ae3/st_login_form-1.2.0.tar.gz",
    "platform": null,
    "description": "<h1 align=\"center\"> \ud83d\udd10 Streamlit Login Form </h1>\n\n<div align=\"center\">\n    <img src=\"https://img.shields.io/pypi/v/st-login-form.svg\" alt=\"PyPI downloads\">\n    <a href=\"https://pepy.tech/project/st-login-form\"> <img src=\"https://static.pepy.tech/personalized-badge/st-login-form?period=total&left_text=Downloads\"> </a>\n    <img src=\"https://img.shields.io/github/license/SiddhantSadangi/st_login_form.svg\" alt=\"License\">\n    <img src=\"https://img.shields.io/badge/PRs-Welcome-brightgreen.svg\" alt=\"PRs Welcome\">\n    <br><br>\n    A Streamlit authentication component that creates a user login form connected to a Supabase DB.\n    <br><br>\n    <img src=\"assets/screenshot.png\" alt=\"App screenshot\">\n</div>\n\n## :balloon: Try the Demo App\n<div align=\"center\">\n    <a href=\"https://st-lgn-form.streamlit.app/\">\n        <img src=\"https://static.streamlit.io/badges/streamlit_badge_black_white.svg\" alt=\"Open in Streamlit\" style=\"height: 60px !important;width: 217px !important;\">\n    </a>\n</div>\n\n## :rocket: Features\n- One-line authentication frontend  \n- Password hashing using the award-winning [Argon2](https://github.com/p-h-c/phc-winner-argon2) algorithm  \n- Inbuilt password constraint checks\n- Create new account, login to existing account, or login as guest\n- Hash existing plaintext passwords in one-line of code\n- Auto-collapses and disables the form on successful authentication\n\n## :building_construction: Installation\n\n1. Install `st-login-form`\n```sh\npip install st-login-form\n```\n2. Create a Supabase project as mentioned [here](https://docs.streamlit.io/knowledge-base/tutorials/databases/supabase#sign-in-to-supabase-and-create-a-project)\n3. Create a table to store the usernames and passwords. A sample DDL query is shown below:\n  ```sql\n  CREATE TABLE users (\n      username text not null default ''::text,\n      password text not null,\n      constraint users_pkey primary key (username),\n      constraint users_username_key unique (username),\n      constraint users_password_check check (\n        (\n          length(\n            trim(\n              both\n              from\n                password\n            )\n          ) > 1\n        )\n      ),\n      constraint users_username_check check (\n        (\n          length(\n            trim(\n              both\n              from\n                username\n            )\n          ) > 1\n        )\n      )\n    ) tablespace pg_default;\n  ```\n4. Follow the rest of the steps from [here](https://docs.streamlit.io/knowledge-base/tutorials/databases/supabase#copy-your-app-secrets-to-the-cloud) to connect your Streamlit app to Supabase\n\n\n## :pen: Usage\n\nOn authentication, `login_form()` sets the `st.session_state['authenticated']` to `True`. This also collapses and disables the login form.  \n`st.session_state['username']` is set to the provided username for a new or existing user, and to `None` for guest login.\n\n```python\nimport streamlit as st\n\nfrom st_login_form import login_form\n\nclient = login_form()\n\nif st.session_state[\"authenticated\"]:\n    if st.session_state[\"username\"]:\n        st.success(f\"Welcome {st.session_state['username']}\")\n        ...\n\n    else:\n        st.success(\"Welcome guest\")\n        ...\nelse:\n    st.error(\"Not authenticated\")\n```\n\n### :key: Hashing existing plaintext passwords\n\nPlaintext password for a user is automatically hashed during a login attempt.\n\nTo bulk-update all existing plaintext passwords in the table, use the `hash_current_passwords()` method.\n\n### :bulb: API Reference\n\n- `login_form()`\n\n  ```python\n    def login_form(\n      *,\n      title: str = \"Authentication\",\n      icon: str = \":material/lock:\",\n      user_tablename: str = \"users\",\n      username_col: str = \"username\",\n      password_col: str = \"password\",\n      constrain_password: bool = True,\n      create_title: str = \":material/add_circle: Create new account\",\n      login_title: str = \":material/login: Login to existing account\",\n      allow_guest: bool = True,\n      allow_create: bool = True,\n      guest_title: str = \":material/visibility_off: Guest login\",\n      create_username_label: str = \"Create a unique username\",\n      create_username_placeholder: str = None,\n      create_username_help: str = None,\n      create_password_label: str = \"Create a password\",\n      create_password_placeholder: str = None,\n      create_password_help: str = \":material/warning: Password cannot be recovered if lost\",\n      create_submit_label: str = \":material/add_circle: Create account\",\n      login_username_label: str = \"Enter your unique username\",\n      login_username_placeholder: str = None,\n      login_username_help: str = None,\n      login_password_label: str = \"Enter your password\",\n      login_password_placeholder: str = None,\n      login_password_help: str = None,\n      login_submit_label: str = \":material/login: Login\",\n      login_error_message: str = \":material/lock: Wrong username/password\",\n      password_constraint_check_fail_message: str = \":material/warning: Password must contain at least 8 characters, including one uppercase letter, one lowercase letter, one number, and one special character (`@$!%*?&_^#- `).\",\n      guest_submit_label: str = \":material/visibility_off: Guest login\",\n  ) -> Client:\n      \"\"\"Creates a user login form in Streamlit apps.\n\n      Connects to a Supabase DB using `SUPABASE_URL` and `SUPABASE_KEY` Streamlit secrets.\n      Sets `session_state[\"authenticated\"]` to True if the login is successful.\n      Sets `session_state[\"username\"]` to provided username or new or existing user, and to `None` for guest login.\n\n      Arguments:\n          title (str): The title of the login form. Default is \"Authentication\".\n          icon (str): The icon to display next to the title. Default is \":material/lock:\".\n          user_tablename (str): The name of the table in the database that stores user information. Default is \"users\".\n          username_col (str): The name of the column in the user table that stores usernames. Default is \"username\".\n          password_col (str): The name of the column in the user table that stores passwords. Default is \"password\".\n          constrain_password (bool): Whether to enforce password constraints (at least 8 characters, including one uppercase letter, one lowercase letter, one number, and one special character (`@$!%*?&_^#- `)). Default is True.\n          create_title (str): The title of the create new account tab. Default is \":material/add_circle: Create new account\".\n          login_title (str): The title of the login to existing account tab. Default is \":material/login: Login to existing account\".\n          allow_guest (bool): Whether to allow guest login. Default is True.\n          allow_create (bool): Whether to allow creating new accounts. Default is True.\n          guest_title (str): The title of the guest login tab. Default is \":material/visibility_off: Guest login\".\n          create_username_label (str): The label for the create username input field. Default is \"Create a unique username\".\n          create_username_placeholder (str): The placeholder text for the create username input field. Default is None.\n          create_username_help (str): The help text for the create username input field. Default is None.\n          create_password_label (str): The label for the create password input field. Default is \"Create a password\".\n          create_password_placeholder (str): The placeholder text for the create password input field. Default is None.\n          create_password_help (str): The help text for the create password input field. Default is \":material/warning: Password cannot be recovered if lost\".\n          create_submit_label (str): The label for the create account submit button. Default is \":material/add_circle: Create account\".\n          login_username_label (str): The label for the login username input field. Default is \"Enter your unique username\".\n          login_username_placeholder (str): The placeholder text for the login username input field. Default is None.\n          login_username_help (str): The help text for the login username input field. Default is None.\n          login_password_label (str): The label for the login password input field. Default is \"Enter your password\".\n          login_password_placeholder (str): The placeholder text for the login password input field. Default is None.\n          login_password_help (str): The help text for the login password input field. Default is None.\n          login_submit_label (str): The label for the login submit button. Default is \":material/login: Login\".\n          login_error_message (str): The error message displayed when the username or password is incorrect. Default is \":material/lock: Wrong username/password\".\n          password_constraint_check_fail_message (str): The error message displayed when the password does not meet the constraints. Default is \":material/warning: Password must contain at least 8 characters, including one uppercase letter, one lowercase letter, one number, and one special character (`@$!%*?&_^#- `).\".\n          guest_submit_label (str): The label for the guest login button. Default is \":material/visibility_off: Guest login\".\n\n      Returns:\n          Supabase.client: The client instance for performing downstream supabase operations.\n      \"\"\"\n  ```\n\n- `hash_current_passwords()`\n\n  ```python\n  def hash_current_passwords(\n      user_tablename: str = \"users\",\n      username_col: str = \"username\",\n      password_col: str = \"password\",\n  ) -> None:\n      \"\"\"Hashes all current plaintext passwords stored in a database table (in-place).\"\"\"\n  ```\n\n## :framed_picture: Gallery\nSome notable Streamlit apps using `st-login-form`\n\n- [SmartExam.io](https://smartexam.io/): SmartExam is an AI app that leverages University lectures to create interactive test exams.\n\n_Want to feature your app? Create a PR!_\n\n## :motorway:  Project Roadmap\nHere are some features that are planned for future releases across the library and demo app. If you want to contribute to any of these features, feel free to open a PR!\n\n### Library Features\n- [ ] Add retype password for confirmation while signing up\n- [ ] Customize password constraints (minimum length, allowed characters, etc.)\n- [ ] Add logout option\n- [ ] Capture additional login metadata - created_at, last_login_at, num_logins, etc.\n- [ ] Add admin panel to set user roles and permissions\n- [ ] Add password recovery option\n- [ ] Support additional databases:\n  - [ ] MySQL\n\n### Demo App Features\n- [ ] Allow users to customise demo login form  \n- [ ] Add code preview for the rendered login form  \n\n## :bow: Acknowledgements\n- [Streamlit](https://streamlit.io) for the amazing Streamlit framework and promoting this library\n- [Ahmed Ramadan](https://www.linkedin.com/in/theahmedrmdan/) for implementing password hashing\n- Everyone who has shared feedback to improve this library!\n\n## :handshake: Get Involved!\nYour feedback and contributions can help shape the future of Streamlit Login Form. If you have ideas or features you'd like to see, let's collaborate!\n\n- **Contribute**: Submit PRs or open issues on GitHub.\n- **Connect**: Have questions or suggestions? Reach out to me on [LinkedIn](https://linkedin.com/in/siddhantsadangi) or [email](mailto:siddhant.sadangi@gmail.com).\n\n\n## :sparkling_heart: Support Streamlit Login Form\nLove Streamlit Login Form? Here's how you can show your support:\n\n- **Star**: Give us a star on GitHub and help spread the word!\n- **Share**: Tell your friends and colleagues about us on social media.\n- **Donate**: Buy me a coffee and fuel further development!\n\n<p align=\"center\">\n    <a href=\"https://www.buymeacoffee.com/siddhantsadangi\" target=\"_blank\"><img src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" alt=\"Buy Me A Coffee\" style=\"height: 60px !important;width: 217px !important;\">\n    </a>\n</p>\n\nThank you for supporting Streamlit Login Form!\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A streamlit component that creates a user login form connected to a Supabase DB. It lets users create a new username and password, login to an existing account, or login as an anonymous guest.",
    "version": "1.2.0",
    "project_urls": {
        "Documentation": "https://github.com/SiddhantSadangi/st_login_form/blob/main/README.md",
        "Funding": "https://www.buymeacoffee.com/siddhantsadangi",
        "Homepage": "https://github.com/SiddhantSadangi/st_login_form"
    },
    "split_keywords": [
        "streamlit",
        " login"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e1f668af70c683fb03c5e263a321b35c575318c14aa612b6e0fd2822e61cc127",
                "md5": "d7373756db1d602f30594e26c6c9dea3",
                "sha256": "f0b7f61ba13373b4c53c582f2fea1d58c0e3d206abfd6808aff00ecd9edcdfe0"
            },
            "downloads": -1,
            "filename": "st_login_form-1.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "d7373756db1d602f30594e26c6c9dea3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 9188,
            "upload_time": "2024-11-03T13:56:24",
            "upload_time_iso_8601": "2024-11-03T13:56:24.279038Z",
            "url": "https://files.pythonhosted.org/packages/e1/f6/68af70c683fb03c5e263a321b35c575318c14aa612b6e0fd2822e61cc127/st_login_form-1.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2c976be7dd6f11c2a9614de575424cb4b1021e74368bd9fe44a2a7a761ce4ae3",
                "md5": "c5a27ed545f687195f1f5f2f8da4b1d3",
                "sha256": "c1b0b83d9ac338645f8858da3914c58e0073d64cbe6fb6cb8e214011285f8d04"
            },
            "downloads": -1,
            "filename": "st_login_form-1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "c5a27ed545f687195f1f5f2f8da4b1d3",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 10971,
            "upload_time": "2024-11-03T13:56:25",
            "upload_time_iso_8601": "2024-11-03T13:56:25.303854Z",
            "url": "https://files.pythonhosted.org/packages/2c/97/6be7dd6f11c2a9614de575424cb4b1021e74368bd9fe44a2a7a761ce4ae3/st_login_form-1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-03 13:56:25",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "SiddhantSadangi",
    "github_project": "st_login_form",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "st-login-form"
}
        
Elapsed time: 0.33127s