vibetuner 2.14.1__py3-none-any.whl → 2.18.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vibetuner might be problematic. Click here for more details.

Files changed (41) hide show
  1. vibetuner/config.py +20 -9
  2. vibetuner/context.py +3 -0
  3. vibetuner/frontend/lifespan.py +12 -7
  4. vibetuner/frontend/middleware.py +2 -2
  5. vibetuner/frontend/routes/debug.py +1 -1
  6. vibetuner/frontend/routes/user.py +1 -1
  7. vibetuner/mongo.py +3 -3
  8. vibetuner/tasks/worker.py +1 -1
  9. vibetuner/templates/email/{default/magic_link.html.jinja → magic_link.html.jinja} +2 -1
  10. vibetuner/templates/frontend/base/favicons.html.jinja +1 -1
  11. vibetuner/templates/frontend/base/skeleton.html.jinja +5 -2
  12. vibetuner/templates/frontend/debug/collections.html.jinja +2 -0
  13. vibetuner/templates/frontend/debug/components/debug_nav.html.jinja +6 -6
  14. vibetuner/templates/frontend/debug/index.html.jinja +6 -4
  15. vibetuner/templates/frontend/debug/info.html.jinja +2 -0
  16. vibetuner/templates/frontend/debug/users.html.jinja +4 -2
  17. vibetuner/templates/frontend/debug/version.html.jinja +2 -0
  18. vibetuner/templates/frontend/email_sent.html.jinja +2 -1
  19. vibetuner/templates/frontend/index.html.jinja +1 -0
  20. vibetuner/templates/frontend/login.html.jinja +8 -3
  21. vibetuner/templates/frontend/user/edit.html.jinja +3 -2
  22. vibetuner/templates/frontend/user/profile.html.jinja +2 -1
  23. {vibetuner-2.14.1.dist-info → vibetuner-2.18.1.dist-info}/METADATA +20 -17
  24. {vibetuner-2.14.1.dist-info → vibetuner-2.18.1.dist-info}/RECORD +27 -41
  25. {vibetuner-2.14.1.dist-info → vibetuner-2.18.1.dist-info}/WHEEL +1 -1
  26. vibetuner/frontend/AGENTS.md +0 -113
  27. vibetuner/frontend/CLAUDE.md +0 -113
  28. vibetuner/models/AGENTS.md +0 -165
  29. vibetuner/models/CLAUDE.md +0 -165
  30. vibetuner/services/AGENTS.md +0 -104
  31. vibetuner/services/CLAUDE.md +0 -104
  32. vibetuner/tasks/AGENTS.md +0 -98
  33. vibetuner/tasks/CLAUDE.md +0 -98
  34. vibetuner/templates/email/AGENTS.md +0 -48
  35. vibetuner/templates/email/CLAUDE.md +0 -48
  36. vibetuner/templates/frontend/AGENTS.md +0 -74
  37. vibetuner/templates/frontend/CLAUDE.md +0 -74
  38. vibetuner/templates/markdown/AGENTS.md +0 -29
  39. vibetuner/templates/markdown/CLAUDE.md +0 -29
  40. /vibetuner/templates/email/{default/magic_link.txt.jinja → magic_link.txt.jinja} +0 -0
  41. {vibetuner-2.14.1.dist-info → vibetuner-2.18.1.dist-info}/entry_points.txt +0 -0
vibetuner/config.py CHANGED
@@ -17,6 +17,8 @@ from pydantic import (
17
17
  from pydantic_extra_types.language_code import LanguageAlpha2
18
18
  from pydantic_settings import BaseSettings, SettingsConfigDict
19
19
 
20
+ from vibetuner.logging import logger
21
+
20
22
  from .paths import config_vars as config_vars_path
21
23
  from .versioning import version
22
24
 
@@ -32,12 +34,16 @@ def _load_project_config() -> "ProjectConfiguration":
32
34
  )
33
35
  if not config_vars_path.exists():
34
36
  return ProjectConfiguration()
35
- return ProjectConfiguration(
36
- **yaml.safe_load(config_vars_path.read_text(encoding="utf-8"))
37
- )
37
+
38
+ yaml_data = yaml.safe_load(config_vars_path.read_text(encoding="utf-8"))
39
+ return ProjectConfiguration(**yaml_data)
38
40
 
39
41
 
40
42
  class ProjectConfiguration(BaseSettings):
43
+ @classmethod
44
+ def from_project_config(cls) -> "ProjectConfiguration":
45
+ return _load_project_config()
46
+
41
47
  project_slug: str = "default_project"
42
48
  project_name: str = "default_project"
43
49
 
@@ -47,9 +53,6 @@ class ProjectConfiguration(BaseSettings):
47
53
  supported_languages: set[LanguageAlpha2] | None = None
48
54
  default_language: LanguageAlpha2 = LanguageAlpha2("en")
49
55
 
50
- mongodb_url: MongoDsn | None = None
51
- redis_url: RedisDsn | None = None
52
-
53
56
  # AWS Parameters
54
57
  aws_default_region: str = "eu-central-1"
55
58
 
@@ -90,16 +93,20 @@ class ProjectConfiguration(BaseSettings):
90
93
  )
91
94
  return f"© {year_part}{f' {self.company_name}' if self.company_name else ''}"
92
95
 
93
- model_config = SettingsConfigDict(extra="ignore")
96
+ model_config = SettingsConfigDict(case_sensitive=False, extra="ignore")
94
97
 
95
98
 
96
99
  class CoreConfiguration(BaseSettings):
97
- project: ProjectConfiguration
100
+ project: ProjectConfiguration = ProjectConfiguration.from_project_config()
98
101
 
99
102
  debug: bool = False
100
103
  version: str = version
101
104
  session_key: SecretStr = SecretStr("ct-!secret-must-change-me")
102
105
 
106
+ # Database and Cache URLs
107
+ mongodb_url: MongoDsn = MongoDsn("mongodb://localhost:27017")
108
+ redis_url: RedisDsn = RedisDsn("redis://localhost:6379")
109
+
103
110
  aws_access_key_id: SecretStr | None = None
104
111
  aws_secret_access_key: SecretStr | None = None
105
112
 
@@ -130,4 +137,8 @@ class CoreConfiguration(BaseSettings):
130
137
  )
131
138
 
132
139
 
133
- settings = CoreConfiguration(project=_load_project_config())
140
+ settings = CoreConfiguration()
141
+
142
+
143
+ logger.info("Configuration loaded for project: {}", settings.project.project_name)
144
+ logger.info("Configuration loaded for project: {}", settings.model_dump())
vibetuner/context.py CHANGED
@@ -23,3 +23,6 @@ class Context(BaseModel):
23
23
  fqdn: str | None = settings.project.fqdn
24
24
 
25
25
  model_config = {"arbitrary_types_allowed": True}
26
+
27
+
28
+ ctx = Context()
@@ -2,25 +2,30 @@ from contextlib import asynccontextmanager
2
2
 
3
3
  from fastapi import FastAPI
4
4
 
5
+ from vibetuner.context import ctx
6
+ from vibetuner.logging import logger
5
7
  from vibetuner.mongo import init_models
6
8
 
7
- from .context import ctx
8
9
  from .hotreload import hotreload
9
10
 
10
11
 
11
12
  @asynccontextmanager
12
- async def lifespan(app: FastAPI):
13
+ async def base_lifespan(app: FastAPI):
14
+ logger.info("Vibetuner frontend starting")
13
15
  if ctx.DEBUG:
14
16
  await hotreload.startup()
15
17
 
16
18
  await init_models()
17
- # Add below anything that should happen before startup
18
19
 
19
- # Until here
20
20
  yield
21
21
 
22
- # Add below anything that should happen before shutdown
23
-
24
- # Until here
22
+ logger.info("Vibetuner frontend stopping")
25
23
  if ctx.DEBUG:
26
24
  await hotreload.shutdown()
25
+ logger.info("Vibetuner frontend stopped")
26
+
27
+
28
+ try:
29
+ from app.frontend.lifespan import lifespan # ty: ignore
30
+ except ImportError:
31
+ lifespan = base_lifespan
@@ -13,12 +13,12 @@ from starlette_babel import (
13
13
  LocaleMiddleware,
14
14
  get_translator,
15
15
  )
16
- from starlette_htmx.middleware import HtmxMiddleware # type: ignore[import-untyped]
16
+ from starlette_htmx.middleware import HtmxMiddleware
17
17
 
18
18
  from vibetuner.config import settings
19
+ from vibetuner.context import ctx
19
20
  from vibetuner.paths import locales as locales_path
20
21
 
21
- from .context import ctx
22
22
  from .oauth import WebUser
23
23
 
24
24
 
@@ -10,10 +10,10 @@ from fastapi.responses import (
10
10
  RedirectResponse,
11
11
  )
12
12
 
13
+ from vibetuner.context import ctx
13
14
  from vibetuner.models import UserModel
14
15
  from vibetuner.models.registry import get_all_models
15
16
 
16
- from ..context import ctx
17
17
  from ..deps import MAGIC_COOKIE_NAME
18
18
  from ..templates import render_template
19
19
 
@@ -3,9 +3,9 @@ from fastapi.responses import HTMLResponse, RedirectResponse
3
3
  from pydantic_extra_types.language_code import LanguageAlpha2
4
4
  from starlette.authentication import requires
5
5
 
6
+ from vibetuner.context import ctx
6
7
  from vibetuner.models import UserModel
7
8
 
8
- from ..context import ctx
9
9
  from ..templates import render_template
10
10
 
11
11
 
vibetuner/mongo.py CHANGED
@@ -1,15 +1,15 @@
1
1
  from beanie import init_beanie
2
2
  from pymongo import AsyncMongoClient
3
3
 
4
- from .config import settings
5
- from .models.registry import get_all_models
4
+ from vibetuner.config import settings
5
+ from vibetuner.models.registry import get_all_models
6
6
 
7
7
 
8
8
  async def init_models() -> None:
9
9
  """Initialize MongoDB connection and register all Beanie models."""
10
10
 
11
11
  client: AsyncMongoClient = AsyncMongoClient(
12
- host=str(settings.project.mongodb_url),
12
+ host=str(settings.mongodb_url),
13
13
  compressors=["zstd"],
14
14
  )
15
15
 
vibetuner/tasks/worker.py CHANGED
@@ -5,7 +5,7 @@ from vibetuner.tasks.context import lifespan
5
5
 
6
6
 
7
7
  worker = Worker(
8
- redis_url=str(settings.project.redis_url),
8
+ redis_url=str(settings.redis_url),
9
9
  queue_name=(
10
10
  settings.project.project_slug
11
11
  if not settings.debug
@@ -1,6 +1,6 @@
1
+ {# djlint:off #}
1
2
  <html>
2
3
  <body>
3
- <h2>Sign in to {{ project_name }}</h2>
4
4
  <p>Click the link below to sign in to your account:</p>
5
5
  <p>
6
6
  <a href="{{ login_url }}"
@@ -14,3 +14,4 @@
14
14
  <p>If you didn't request this, you can safely ignore this email.</p>
15
15
  </body>
16
16
  </html>
17
+ {# djlint:on #}
@@ -1 +1 @@
1
- <link rel="manifest" href="{{ url_for("site_webmanifest").path }}" />
1
+ <link rel="manifest" href="{{ url_for('site_webmanifest').path }}" />
@@ -3,8 +3,8 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <meta name="description" content="{{ meta_description | default("") }}" />
7
- <meta name="keywords" content="{{ meta_keywords | default("") }}" />
6
+ <meta name="description" content="{{ meta_description | default('') }}" />
7
+ <meta name="keywords" content="{{ meta_keywords | default('') }}" />
8
8
  <meta name="color-scheme" content="light" />
9
9
  <title>
10
10
  {% block title %}
@@ -17,6 +17,7 @@
17
17
  {% endif %}
18
18
  {% include "base/favicons.html.jinja" %}
19
19
  {% include "base/opengraph.html.jinja" %}
20
+
20
21
  {% block head %}
21
22
  {% endblock head %}
22
23
  </head>
@@ -26,6 +27,7 @@
26
27
  {% block header %}
27
28
  {% if not SKIP_HEADER %}
28
29
  {% include "base/header.html.jinja" %}
30
+
29
31
  {% endif %}
30
32
  {% endblock header %}
31
33
  {% block body %}
@@ -33,6 +35,7 @@
33
35
  {% block footer %}
34
36
  {% if not SKIP_FOOTER %}
35
37
  {% include "base/footer.html.jinja" %}
38
+
36
39
  {% endif %}
37
40
  {% endblock footer %}
38
41
  {% if DEBUG %}{{ hotreload.script(url_for('hot-reload') ) | safe }}{% endif %}
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  Database Collections Schema - Debug
4
5
  {% endblock title %}
@@ -99,5 +100,6 @@
99
100
  </div>
100
101
  <!-- Debug Navigation Footer -->
101
102
  {% include "debug/components/debug_nav.html.jinja" %}
103
+
102
104
  </div>
103
105
  {% endblock body %}
@@ -1,7 +1,7 @@
1
1
  <!-- Debug Navigation Component -->
2
2
  <nav class="mt-8 pt-6 border-t border-base-200">
3
3
  <div class="flex flex-wrap gap-4">
4
- <a href="{{ url_for("debug_index") }}"
4
+ <a href="{{ url_for('debug_index') }}"
5
5
  class="btn btn-outline btn-primary gap-2">
6
6
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
7
7
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z">
@@ -11,7 +11,7 @@
11
11
  </svg>
12
12
  Debug Home
13
13
  </a>
14
- <a href="{{ url_for("debug_info") }}"
14
+ <a href="{{ url_for('debug_info') }}"
15
15
  class="btn btn-outline btn-primary gap-2">
16
16
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
17
17
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z">
@@ -19,7 +19,7 @@
19
19
  </svg>
20
20
  System Info
21
21
  </a>
22
- <a href="{{ url_for("debug_collections") }}"
22
+ <a href="{{ url_for('debug_collections') }}"
23
23
  class="btn btn-outline btn-primary gap-2">
24
24
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
25
25
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4">
@@ -27,7 +27,7 @@
27
27
  </svg>
28
28
  Collections
29
29
  </a>
30
- <a href="{{ url_for("debug_users") }}"
30
+ <a href="{{ url_for('debug_users') }}"
31
31
  class="btn btn-outline btn-warning gap-2">
32
32
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
33
33
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z">
@@ -35,7 +35,7 @@
35
35
  </svg>
36
36
  User Impersonation
37
37
  </a>
38
- <a href="{{ url_for("debug_version") }}"
38
+ <a href="{{ url_for('debug_version') }}"
39
39
  class="btn btn-outline btn-primary gap-2">
40
40
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
41
41
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z">
@@ -43,7 +43,7 @@
43
43
  </svg>
44
44
  Version
45
45
  </a>
46
- <a href="{{ url_for("health_ping") }}"
46
+ <a href="{{ url_for('health_ping') }}"
47
47
  class="btn btn-outline btn-success gap-2">
48
48
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
49
49
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z">
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  Debug Dashboard
4
5
  {% endblock title %}
@@ -23,7 +24,7 @@
23
24
  </h2>
24
25
  <p class="text-base-content/70 mb-4">View application configuration, cookies, and runtime information</p>
25
26
  <div class="card-actions justify-end">
26
- <a href="{{ url_for("debug_info") }}" class="btn btn-primary btn-sm">View Details</a>
27
+ <a href="{{ url_for('debug_info') }}" class="btn btn-primary btn-sm">View Details</a>
27
28
  </div>
28
29
  </div>
29
30
  </div>
@@ -39,7 +40,7 @@
39
40
  </h2>
40
41
  <p class="text-base-content/70 mb-4">Explore MongoDB collections and their field schemas</p>
41
42
  <div class="card-actions justify-end">
42
- <a href="{{ url_for("debug_collections") }}"
43
+ <a href="{{ url_for('debug_collections') }}"
43
44
  class="btn btn-primary btn-sm">View Schemas</a>
44
45
  </div>
45
46
  </div>
@@ -56,7 +57,7 @@
56
57
  </h2>
57
58
  <p class="text-base-content/70 mb-4">Check application version and build information</p>
58
59
  <div class="card-actions justify-end">
59
- <a href="{{ url_for("debug_version") }}" class="btn btn-primary btn-sm">View Version</a>
60
+ <a href="{{ url_for('debug_version') }}" class="btn btn-primary btn-sm">View Version</a>
60
61
  </div>
61
62
  </div>
62
63
  </div>
@@ -72,12 +73,13 @@
72
73
  </h2>
73
74
  <p class="text-base-content/70 mb-4">Verify application health and API endpoint status</p>
74
75
  <div class="card-actions justify-end">
75
- <a href="{{ url_for("health_ping") }}" class="btn btn-success btn-sm">Check Health</a>
76
+ <a href="{{ url_for('health_ping') }}" class="btn btn-success btn-sm">Check Health</a>
76
77
  </div>
77
78
  </div>
78
79
  </div>
79
80
  </div>
80
81
  <!-- Debug Navigation Footer -->
81
82
  {% include "debug/components/debug_nav.html.jinja" %}
83
+
82
84
  </div>
83
85
  {% endblock body %}
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  System Information - Debug
4
5
  {% endblock title %}
@@ -252,5 +253,6 @@
252
253
  </div>
253
254
  <!-- Debug Navigation Footer -->
254
255
  {% include "debug/components/debug_nav.html.jinja" %}
256
+
255
257
  </div>
256
258
  {% endblock body %}
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  Debug - User Impersonation
4
5
  {% endblock title %}
@@ -36,7 +37,7 @@
36
37
  User ID: <code>{{ current_user_id }}</code>
37
38
  </p>
38
39
  <div class="card-actions justify-end">
39
- <form method="post" action="/debug/stop-impersonation">
40
+ <form method="post" action="{{ url_for('debug.stop_impersonation') }}">
40
41
  <button type="submit" class="btn btn-secondary btn-sm">Stop Impersonation</button>
41
42
  </form>
42
43
  </div>
@@ -105,7 +106,7 @@
105
106
  <td class="text-center">
106
107
  {% if current_user_id != user.id|string %}
107
108
  <form method="post"
108
- action="/debug/impersonate/{{ user.id }}"
109
+ action="{{ url_for('debug.impersonate_user', user_id=user.id) }}"
109
110
  class="inline">
110
111
  <button type="submit" class="btn btn-outline btn-sm">Impersonate</button>
111
112
  </form>
@@ -133,5 +134,6 @@
133
134
  </div>
134
135
  <!-- Debug Navigation Footer -->
135
136
  {% include "debug/components/debug_nav.html.jinja" %}
137
+
136
138
  </div>
137
139
  {% endblock body %}
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  Version Information - Debug
4
5
  {% endblock title %}
@@ -49,5 +50,6 @@
49
50
  </div>
50
51
  <!-- Debug Navigation Footer -->
51
52
  {% include "debug/components/debug_nav.html.jinja" %}
53
+
52
54
  </div>
53
55
  {% endblock body %}
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  {{ _("Check Your Email") }}
4
5
  {% endblock title %}
@@ -64,7 +65,7 @@
64
65
  {{ _("Try Again") }}
65
66
  </a>
66
67
  <!-- Back to Home -->
67
- <a href="{{ url_for("homepage") }}"
68
+ <a href="{{ url_for('homepage') }}"
68
69
  class="btn btn-ghost btn-block gap-2 text-base-content/70 hover:text-base-content transition-all duration-300">
69
70
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
70
71
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
@@ -1,5 +1,6 @@
1
1
  {% set BODY_CLASS = "min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 flex flex-col justify-between" %}
2
2
  {% extends "base/skeleton.html.jinja" %}
3
+
3
4
  {% block body %}
4
5
  <!-- Main Content -->
5
6
  <div class="flex-1 flex items-center justify-center px-6">
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  {{ _("Sign In") }}
4
5
  {% endblock title %}
@@ -15,7 +16,11 @@
15
16
  {% if has_oauth and providers %}
16
17
  <div class="space-y-3 mb-6">
17
18
  {% for provider in providers %}
18
- <a href="{{ url_for('login_with_' + provider) }}{%- if next %}?next={{ next }}{%- endif %}"
19
+ {% set login_url = url_for('login_with_' + provider) %}
20
+ {% if next %}
21
+ {% set login_url = login_url ~ '?next=' ~ next %}
22
+ {% endif %}
23
+ <a href="{{ login_url }}"
19
24
  class="btn btn-outline btn-block justify-start gap-3 hover:btn-primary group transition-all duration-300 hover:scale-[1.02]">
20
25
  <span>{{ _("Continue with %(provider)s") | format(provider=provider.title()) }}</span>
21
26
  </a>
@@ -29,7 +34,7 @@
29
34
  <div class="bg-base-200/50 rounded-2xl p-6 border border-base-300/50">
30
35
  <form method="post"
31
36
  class="space-y-4"
32
- action="{{ url_for("send_magic_link") }}">
37
+ action="{{ url_for('send_magic_link') }}">
33
38
  {% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
34
39
  <div class="form-control">
35
40
  <label class="label" for="email">
@@ -40,7 +45,7 @@
40
45
  id="email"
41
46
  name="email"
42
47
  class="input input-bordered w-full pr-12 focus:input-primary transition-all duration-300"
43
- placeholder="{{ _("Enter your email address") }}"
48
+ placeholder="{{ _('Enter your email address') }}"
44
49
  required
45
50
  autocomplete="email" />
46
51
  <div class="absolute inset-y-0 right-0 flex items-center pr-3">
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  {{ _("Edit Profile") }}
4
5
  {% endblock title %}
@@ -13,7 +14,7 @@
13
14
  </div>
14
15
  <!-- Edit Form -->
15
16
  <div class="bg-white shadow-lg rounded-lg p-6">
16
- <form method="post" action="{{ url_for("user_edit_submit") }}">
17
+ <form method="post" action="{{ url_for('user_edit_submit') }}">
17
18
  <div class="space-y-6">
18
19
  <!-- Name Field -->
19
20
  <div>
@@ -55,7 +56,7 @@
55
56
  </div>
56
57
  <!-- Form Actions -->
57
58
  <div class="flex justify-between items-center mt-8 pt-6 border-t border-gray-200">
58
- <a href="{{ url_for("user_profile") }}" class="btn btn-ghost">{{ _("Cancel") }}</a>
59
+ <a href="{{ url_for('user_profile') }}" class="btn btn-ghost">{{ _("Cancel") }}</a>
59
60
  <button type="submit" class="btn btn-primary">{{ _("Save Changes") }}</button>
60
61
  </div>
61
62
  </form>
@@ -1,4 +1,5 @@
1
1
  {% extends "base/skeleton.html.jinja" %}
2
+
2
3
  {% block title %}
3
4
  {{ _("User Profile") }}
4
5
  {% endblock title %}
@@ -108,7 +109,7 @@
108
109
  hx-get="/user/edit"
109
110
  hx-target="#main-content"
110
111
  hx-swap="innerHTML">{{ _("Edit Profile") }}</button>
111
- <a href="{{ url_for("auth_logout") }}" class="btn btn-outline btn-error">{{ _("Sign Out") }}</a>
112
+ <a href="{{ url_for('auth_logout') }}" class="btn btn-outline btn-error">{{ _("Sign Out") }}</a>
112
113
  </div>
113
114
  </div>
114
115
  </div>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: vibetuner
3
- Version: 2.14.1
3
+ Version: 2.18.1
4
4
  Summary: Core Python framework and blessed dependencies for production-ready FastAPI + MongoDB + HTMX projects
5
5
  Keywords: fastapi,mongodb,htmx,web-framework,scaffolding,oauth,background-jobs
6
6
  Author: All Tuner Labs, S.L.
@@ -24,14 +24,14 @@ Requires-Dist: beanie[zstd]>=2.0.0
24
24
  Requires-Dist: click>=8.3.0
25
25
  Requires-Dist: copier>=9.10.3,<9.10.4
26
26
  Requires-Dist: email-validator>=2.3.0
27
- Requires-Dist: fastapi[standard-no-fastapi-cloud-cli]>=0.121.0
27
+ Requires-Dist: fastapi[standard-no-fastapi-cloud-cli]>=0.121.1
28
28
  Requires-Dist: granian[pname]>=2.5.7
29
29
  Requires-Dist: httpx[http2]>=0.28.1
30
30
  Requires-Dist: itsdangerous>=2.2.0
31
31
  Requires-Dist: loguru>=0.7.3
32
32
  Requires-Dist: pydantic[email]>=2.12.4
33
33
  Requires-Dist: pydantic-extra-types[pycountry]>=2.10.6
34
- Requires-Dist: pydantic-settings>=2.11.0
34
+ Requires-Dist: pydantic-settings>=2.12.0
35
35
  Requires-Dist: pyyaml>=6.0.3
36
36
  Requires-Dist: redis[hiredis]>=7.0.1
37
37
  Requires-Dist: rich>=14.2.0
@@ -44,24 +44,24 @@ Requires-Dist: babel>=2.17.0 ; extra == 'dev'
44
44
  Requires-Dist: cloudflare>=4.3.1 ; extra == 'dev'
45
45
  Requires-Dist: djlint>=1.36.4 ; extra == 'dev'
46
46
  Requires-Dist: dunamai>=1.25.0 ; extra == 'dev'
47
- Requires-Dist: gh-bin>=2.81.0 ; extra == 'dev'
47
+ Requires-Dist: gh-bin>=2.83.0 ; extra == 'dev'
48
48
  Requires-Dist: granian[pname,reload]>=2.5.7 ; extra == 'dev'
49
49
  Requires-Dist: just-bin>=1.43.0 ; extra == 'dev'
50
- Requires-Dist: pre-commit>=4.3.0 ; extra == 'dev'
50
+ Requires-Dist: pre-commit>=4.4.0 ; extra == 'dev'
51
51
  Requires-Dist: pysemver>=0.5.0 ; extra == 'dev'
52
- Requires-Dist: ruff>=0.14.3 ; extra == 'dev'
53
- Requires-Dist: rumdl>=0.0.171 ; extra == 'dev'
52
+ Requires-Dist: ruff>=0.14.4 ; extra == 'dev'
53
+ Requires-Dist: rumdl>=0.0.174 ; extra == 'dev'
54
54
  Requires-Dist: semver>=3.0.4 ; extra == 'dev'
55
55
  Requires-Dist: taplo>=0.9.3 ; extra == 'dev'
56
- Requires-Dist: ty>=0.0.1a25 ; extra == 'dev'
56
+ Requires-Dist: ty>=0.0.1a26 ; extra == 'dev'
57
57
  Requires-Dist: types-aioboto3[s3,ses]>=15.5.0 ; extra == 'dev'
58
58
  Requires-Dist: types-authlib>=1.6.5.20251005 ; extra == 'dev'
59
59
  Requires-Dist: types-pyyaml>=6.0.12.20250915 ; extra == 'dev'
60
60
  Requires-Dist: uv-bump>=0.3.1 ; extra == 'dev'
61
61
  Requires-Python: >=3.11
62
62
  Project-URL: Changelog, https://github.com/alltuner/vibetuner/blob/main/CHANGELOG.md
63
- Project-URL: Documentation, https://github.com/alltuner/vibetuner#readme
64
- Project-URL: Homepage, https://github.com/alltuner/vibetuner
63
+ Project-URL: Documentation, https://vibetuner.alltuner.com/
64
+ Project-URL: Homepage, https://vibetuner.alltuner.com/
65
65
  Project-URL: Issues, https://github.com/alltuner/vibetuner/issues
66
66
  Project-URL: Repository, https://github.com/alltuner/vibetuner
67
67
  Provides-Extra: dev
@@ -69,13 +69,16 @@ Description-Content-Type: text/markdown
69
69
 
70
70
  # vibetuner
71
71
 
72
- **Core Python framework and blessed dependencies for Vibetuner projects**
72
+ Core Python framework and blessed dependencies for Vibetuner projects
73
73
 
74
- This package provides the complete Python framework and curated dependency set for building modern web applications with Vibetuner. It includes everything from FastAPI and MongoDB integration to authentication, background jobs, and CLI tools.
74
+ This package provides the complete Python framework and curated dependency set for building modern
75
+ web applications with Vibetuner. It includes everything from FastAPI and MongoDB integration to
76
+ authentication, background jobs, and CLI tools.
75
77
 
76
78
  ## What is Vibetuner?
77
79
 
78
- Vibetuner is a production-ready scaffolding tool for FastAPI + MongoDB + HTMX web applications. This package (`vibetuner`) is the Python component that provides:
80
+ Vibetuner is a production-ready scaffolding tool for FastAPI + MongoDB + HTMX web applications.
81
+ This package (`vibetuner`) is the Python component that provides:
79
82
 
80
83
  - Complete web application framework built on FastAPI
81
84
  - MongoDB integration with Beanie ODM
@@ -84,7 +87,8 @@ Vibetuner is a production-ready scaffolding tool for FastAPI + MongoDB + HTMX we
84
87
  - CLI framework with Typer
85
88
  - Email services, blob storage, and more
86
89
 
87
- **This package is designed to be used within projects generated by the Vibetuner scaffolding tool.** For standalone use, you'll need to set up the project structure manually.
90
+ **This package is designed to be used within projects generated by the Vibetuner scaffolding
91
+ tool.** For standalone use, you'll need to set up the project structure manually.
88
92
 
89
93
  ## Installation
90
94
 
@@ -172,7 +176,6 @@ vibetuner run prod worker
172
176
  The `[dev]` extra includes all tools needed for development:
173
177
 
174
178
  - **Ruff**: Fast linting and formatting
175
- - **djlint**: Template linting
176
179
  - **Babel**: i18n message extraction
177
180
  - **pre-commit**: Git hooks
178
181
  - **Type stubs**: For aioboto3, authlib, PyYAML
@@ -205,7 +208,7 @@ async def hello():
205
208
 
206
209
  For complete documentation, guides, and examples, see the main Vibetuner repository:
207
210
 
208
- **📖 [Vibetuner Documentation](https://github.com/alltuner/vibetuner#readme)**
211
+ **📖 [Vibetuner Documentation](https://vibetuner.alltuner.com/)**
209
212
 
210
213
  ## Package Ecosystem
211
214
 
@@ -232,7 +235,7 @@ See [LICENSE](https://github.com/alltuner/vibetuner/blob/main/LICENSE) for detai
232
235
  ## Links
233
236
 
234
237
  - **Main Repository**: <https://github.com/alltuner/vibetuner>
235
- - **Documentation**: <https://github.com/alltuner/vibetuner#readme>
238
+ - **Documentation**: <https://vibetuner.alltuner.com/>
236
239
  - **Issues**: <https://github.com/alltuner/vibetuner/issues>
237
240
  - **PyPI**: <https://pypi.org/project/vibetuner/>
238
241
  - **npm Package**: <https://www.npmjs.com/package/@alltuner/vibetuner>