vibetuner 2.7.0__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.
- vibetuner/cli/__init__.py +13 -2
- vibetuner/cli/run.py +0 -1
- vibetuner/cli/scaffold.py +187 -0
- vibetuner/config.py +27 -11
- vibetuner/context.py +3 -0
- vibetuner/frontend/__init__.py +7 -2
- vibetuner/frontend/lifespan.py +12 -7
- vibetuner/frontend/middleware.py +3 -3
- vibetuner/frontend/routes/auth.py +19 -13
- vibetuner/frontend/routes/debug.py +1 -1
- vibetuner/frontend/routes/health.py +4 -0
- vibetuner/frontend/routes/user.py +1 -1
- vibetuner/mongo.py +1 -1
- vibetuner/paths.py +197 -80
- vibetuner/tasks/worker.py +1 -1
- vibetuner/templates/email/{default/magic_link.html.jinja → magic_link.html.jinja} +2 -1
- vibetuner/templates/frontend/base/favicons.html.jinja +1 -1
- vibetuner/templates/frontend/base/skeleton.html.jinja +5 -2
- vibetuner/templates/frontend/debug/collections.html.jinja +2 -0
- vibetuner/templates/frontend/debug/components/debug_nav.html.jinja +6 -6
- vibetuner/templates/frontend/debug/index.html.jinja +6 -4
- vibetuner/templates/frontend/debug/info.html.jinja +2 -0
- vibetuner/templates/frontend/debug/users.html.jinja +4 -2
- vibetuner/templates/frontend/debug/version.html.jinja +2 -0
- vibetuner/templates/frontend/email_sent.html.jinja +2 -1
- vibetuner/templates/frontend/index.html.jinja +1 -0
- vibetuner/templates/frontend/login.html.jinja +8 -3
- vibetuner/templates/frontend/user/edit.html.jinja +3 -2
- vibetuner/templates/frontend/user/profile.html.jinja +2 -1
- vibetuner/templates.py +9 -15
- vibetuner/versioning.py +1 -1
- vibetuner-2.18.1.dist-info/METADATA +241 -0
- vibetuner-2.18.1.dist-info/RECORD +72 -0
- {vibetuner-2.7.0.dist-info → vibetuner-2.18.1.dist-info}/WHEEL +1 -1
- vibetuner-2.18.1.dist-info/entry_points.txt +3 -0
- vibetuner/frontend/AGENTS.md +0 -113
- vibetuner/frontend/CLAUDE.md +0 -113
- vibetuner/models/AGENTS.md +0 -165
- vibetuner/models/CLAUDE.md +0 -165
- vibetuner/services/AGENTS.md +0 -104
- vibetuner/services/CLAUDE.md +0 -104
- vibetuner/tasks/AGENTS.md +0 -98
- vibetuner/tasks/CLAUDE.md +0 -98
- vibetuner/templates/email/AGENTS.md +0 -48
- vibetuner/templates/email/CLAUDE.md +0 -48
- vibetuner/templates/frontend/AGENTS.md +0 -74
- vibetuner/templates/frontend/CLAUDE.md +0 -74
- vibetuner/templates/markdown/AGENTS.md +0 -29
- vibetuner/templates/markdown/CLAUDE.md +0 -29
- vibetuner-2.7.0.dist-info/METADATA +0 -48
- vibetuner-2.7.0.dist-info/RECORD +0 -84
- /vibetuner/templates/email/{default/magic_link.txt.jinja → magic_link.txt.jinja} +0 -0
vibetuner/cli/__init__.py
CHANGED
|
@@ -9,7 +9,7 @@ import typer
|
|
|
9
9
|
from rich.console import Console
|
|
10
10
|
|
|
11
11
|
from vibetuner.cli.run import run_app
|
|
12
|
-
from vibetuner.
|
|
12
|
+
from vibetuner.cli.scaffold import scaffold_app
|
|
13
13
|
from vibetuner.logging import LogLevel, setup_logging
|
|
14
14
|
|
|
15
15
|
|
|
@@ -43,7 +43,16 @@ class AsyncTyper(typer.Typer):
|
|
|
43
43
|
return partial(self.maybe_run_async, decorator)
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
def _get_app_help():
|
|
47
|
+
try:
|
|
48
|
+
from vibetuner.config import settings
|
|
49
|
+
|
|
50
|
+
return f"{settings.project.project_name.title()} CLI"
|
|
51
|
+
except (RuntimeError, ImportError):
|
|
52
|
+
return "Vibetuner CLI"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
app = AsyncTyper(help=_get_app_help())
|
|
47
56
|
|
|
48
57
|
LOG_LEVEL_OPTION = typer.Option(
|
|
49
58
|
LogLevel.INFO,
|
|
@@ -61,8 +70,10 @@ def callback(log_level: LogLevel | None = LOG_LEVEL_OPTION) -> None:
|
|
|
61
70
|
|
|
62
71
|
|
|
63
72
|
app.add_typer(run_app, name="run")
|
|
73
|
+
app.add_typer(scaffold_app, name="scaffold")
|
|
64
74
|
|
|
65
75
|
try:
|
|
66
76
|
import_module("app.cli")
|
|
67
77
|
except (ImportError, ModuleNotFoundError):
|
|
68
78
|
pass
|
|
79
|
+
# Cache buster
|
vibetuner/cli/run.py
CHANGED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# ABOUTME: Scaffolding commands for creating new projects from the vibetuner template
|
|
2
|
+
# ABOUTME: Uses Copier to generate FastAPI+MongoDB+HTMX projects with interactive prompts
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
import copier
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
console = Console()
|
|
12
|
+
|
|
13
|
+
scaffold_app = typer.Typer(
|
|
14
|
+
help="Create new projects from the vibetuner template", no_args_is_help=True
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@scaffold_app.command(name="new")
|
|
19
|
+
def new(
|
|
20
|
+
destination: Annotated[
|
|
21
|
+
Path,
|
|
22
|
+
typer.Argument(
|
|
23
|
+
help="Destination directory for the new project",
|
|
24
|
+
exists=False,
|
|
25
|
+
),
|
|
26
|
+
],
|
|
27
|
+
defaults: Annotated[
|
|
28
|
+
bool,
|
|
29
|
+
typer.Option(
|
|
30
|
+
"--defaults",
|
|
31
|
+
"-d",
|
|
32
|
+
help="Use default values for all prompts (non-interactive mode)",
|
|
33
|
+
),
|
|
34
|
+
] = False,
|
|
35
|
+
data: Annotated[
|
|
36
|
+
list[str] | None,
|
|
37
|
+
typer.Option(
|
|
38
|
+
"--data",
|
|
39
|
+
help="Override template variables in key=value format (can be used multiple times)",
|
|
40
|
+
),
|
|
41
|
+
] = None,
|
|
42
|
+
branch: Annotated[
|
|
43
|
+
str | None,
|
|
44
|
+
typer.Option(
|
|
45
|
+
"--branch",
|
|
46
|
+
"-b",
|
|
47
|
+
help="Use specific branch/tag from the vibetuner template repository",
|
|
48
|
+
),
|
|
49
|
+
] = None,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Create a new project from the vibetuner template.
|
|
52
|
+
|
|
53
|
+
Examples:
|
|
54
|
+
|
|
55
|
+
# Interactive mode (prompts for all values)
|
|
56
|
+
vibetuner scaffold new my-project
|
|
57
|
+
|
|
58
|
+
# Use defaults for all prompts
|
|
59
|
+
vibetuner scaffold new my-project --defaults
|
|
60
|
+
|
|
61
|
+
# Override specific values
|
|
62
|
+
vibetuner scaffold new my-project --data project_name="My App" --data python_version="3.13"
|
|
63
|
+
|
|
64
|
+
# Use specific branch for testing
|
|
65
|
+
vibetuner scaffold new my-project --branch fix/scaffold-command
|
|
66
|
+
"""
|
|
67
|
+
# Use the official vibetuner template from GitHub
|
|
68
|
+
template_src = "gh:alltuner/vibetuner"
|
|
69
|
+
vcs_ref = branch or "main" # Use specified branch or default to main
|
|
70
|
+
|
|
71
|
+
if branch:
|
|
72
|
+
console.print(
|
|
73
|
+
f"[dim]Using vibetuner template from GitHub ({branch} branch)[/dim]"
|
|
74
|
+
)
|
|
75
|
+
else:
|
|
76
|
+
console.print("[dim]Using vibetuner template from GitHub (main branch)[/dim]")
|
|
77
|
+
|
|
78
|
+
# Parse data overrides
|
|
79
|
+
data_dict = {}
|
|
80
|
+
if data:
|
|
81
|
+
for item in data:
|
|
82
|
+
if "=" not in item:
|
|
83
|
+
console.print(
|
|
84
|
+
f"[red]Error: Invalid data format '{item}'. Expected key=value[/red]"
|
|
85
|
+
)
|
|
86
|
+
raise typer.Exit(code=1)
|
|
87
|
+
key, value = item.split("=", 1)
|
|
88
|
+
data_dict[key] = value
|
|
89
|
+
|
|
90
|
+
# When using defaults, provide sensible default values for required fields
|
|
91
|
+
if defaults:
|
|
92
|
+
default_values = {
|
|
93
|
+
"company_name": "Acme Corp",
|
|
94
|
+
"author_name": "Developer",
|
|
95
|
+
"author_email": "dev@example.com",
|
|
96
|
+
"supported_languages": [],
|
|
97
|
+
}
|
|
98
|
+
# Merge: user overrides take precedence over defaults
|
|
99
|
+
data_dict = {**default_values, **data_dict}
|
|
100
|
+
|
|
101
|
+
# Run copier
|
|
102
|
+
try:
|
|
103
|
+
console.print(f"\n[green]Creating new project in: {destination}[/green]\n")
|
|
104
|
+
|
|
105
|
+
copier.run_copy(
|
|
106
|
+
src_path=str(template_src),
|
|
107
|
+
dst_path=destination,
|
|
108
|
+
data=data_dict if data_dict else None,
|
|
109
|
+
defaults=defaults,
|
|
110
|
+
quiet=defaults, # Suppress prompts when using defaults
|
|
111
|
+
unsafe=True, # Allow running post-generation tasks
|
|
112
|
+
vcs_ref=vcs_ref, # Use the specified branch or default to main
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
console.print("\n[green]✓ Project created successfully![/green]")
|
|
116
|
+
console.print("\nNext steps:")
|
|
117
|
+
console.print(f" cd {destination}")
|
|
118
|
+
console.print(" just dev")
|
|
119
|
+
|
|
120
|
+
except Exception as e:
|
|
121
|
+
console.print(f"[red]Error creating project: {e}[/red]")
|
|
122
|
+
raise typer.Exit(code=1) from None
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@scaffold_app.command(name="update")
|
|
126
|
+
def update(
|
|
127
|
+
path: Annotated[
|
|
128
|
+
Path | None,
|
|
129
|
+
typer.Argument(
|
|
130
|
+
help="Path to the project to update",
|
|
131
|
+
),
|
|
132
|
+
] = None,
|
|
133
|
+
skip_answered: Annotated[
|
|
134
|
+
bool,
|
|
135
|
+
typer.Option(
|
|
136
|
+
"--skip-answered",
|
|
137
|
+
"-s",
|
|
138
|
+
help="Skip questions that have already been answered",
|
|
139
|
+
),
|
|
140
|
+
] = True,
|
|
141
|
+
) -> None:
|
|
142
|
+
"""Update an existing project to the latest template version.
|
|
143
|
+
|
|
144
|
+
This will update the project's files to match the latest template version,
|
|
145
|
+
while preserving your answers to the original questions.
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
|
|
149
|
+
# Update current directory
|
|
150
|
+
vibetuner scaffold update
|
|
151
|
+
|
|
152
|
+
# Update specific directory
|
|
153
|
+
vibetuner scaffold update /path/to/project
|
|
154
|
+
|
|
155
|
+
# Re-prompt for all questions
|
|
156
|
+
vibetuner scaffold update --no-skip-answered
|
|
157
|
+
"""
|
|
158
|
+
if path is None:
|
|
159
|
+
path = Path.cwd()
|
|
160
|
+
|
|
161
|
+
if not path.exists():
|
|
162
|
+
console.print(f"[red]Error: Directory does not exist: {path}[/red]")
|
|
163
|
+
raise typer.Exit(code=1)
|
|
164
|
+
|
|
165
|
+
# Check if it's a copier project
|
|
166
|
+
answers_file = path / ".copier-answers.yml"
|
|
167
|
+
if not answers_file.exists():
|
|
168
|
+
console.print(
|
|
169
|
+
"[red]Error: Not a copier project (missing .copier-answers.yml)[/red]"
|
|
170
|
+
)
|
|
171
|
+
console.print(f"[yellow]Directory: {path}[/yellow]")
|
|
172
|
+
raise typer.Exit(code=1)
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
console.print(f"\n[green]Updating project: {path}[/green]\n")
|
|
176
|
+
|
|
177
|
+
copier.run_update(
|
|
178
|
+
dst_path=path,
|
|
179
|
+
skip_answered=skip_answered,
|
|
180
|
+
unsafe=True, # Allow running post-generation tasks
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
console.print("\n[green]✓ Project updated successfully![/green]")
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
console.print(f"[red]Error updating project: {e}[/red]")
|
|
187
|
+
raise typer.Exit(code=1) from None
|
vibetuner/config.py
CHANGED
|
@@ -17,22 +17,33 @@ 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.
|
|
21
|
-
|
|
20
|
+
from vibetuner.logging import logger
|
|
21
|
+
|
|
22
|
+
from .paths import config_vars as config_vars_path
|
|
23
|
+
from .versioning import version
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
current_year: int = datetime.now().year
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def _load_project_config() -> "ProjectConfiguration":
|
|
30
|
+
if config_vars_path is None:
|
|
31
|
+
raise RuntimeError(
|
|
32
|
+
"Project root not detected. Cannot load project configuration. "
|
|
33
|
+
"Ensure you're running from within a project directory with .copier-answers.yml"
|
|
34
|
+
)
|
|
28
35
|
if not config_vars_path.exists():
|
|
29
36
|
return ProjectConfiguration()
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
37
|
+
|
|
38
|
+
yaml_data = yaml.safe_load(config_vars_path.read_text(encoding="utf-8"))
|
|
39
|
+
return ProjectConfiguration(**yaml_data)
|
|
33
40
|
|
|
34
41
|
|
|
35
42
|
class ProjectConfiguration(BaseSettings):
|
|
43
|
+
@classmethod
|
|
44
|
+
def from_project_config(cls) -> "ProjectConfiguration":
|
|
45
|
+
return _load_project_config()
|
|
46
|
+
|
|
36
47
|
project_slug: str = "default_project"
|
|
37
48
|
project_name: str = "default_project"
|
|
38
49
|
|
|
@@ -42,9 +53,6 @@ class ProjectConfiguration(BaseSettings):
|
|
|
42
53
|
supported_languages: set[LanguageAlpha2] | None = None
|
|
43
54
|
default_language: LanguageAlpha2 = LanguageAlpha2("en")
|
|
44
55
|
|
|
45
|
-
mongodb_url: MongoDsn | None = None
|
|
46
|
-
redis_url: RedisDsn | None = None
|
|
47
|
-
|
|
48
56
|
# AWS Parameters
|
|
49
57
|
aws_default_region: str = "eu-central-1"
|
|
50
58
|
|
|
@@ -85,16 +93,20 @@ class ProjectConfiguration(BaseSettings):
|
|
|
85
93
|
)
|
|
86
94
|
return f"© {year_part}{f' {self.company_name}' if self.company_name else ''}"
|
|
87
95
|
|
|
88
|
-
model_config = SettingsConfigDict(extra="ignore")
|
|
96
|
+
model_config = SettingsConfigDict(case_sensitive=False, extra="ignore")
|
|
89
97
|
|
|
90
98
|
|
|
91
99
|
class CoreConfiguration(BaseSettings):
|
|
92
|
-
project: ProjectConfiguration
|
|
100
|
+
project: ProjectConfiguration = ProjectConfiguration.from_project_config()
|
|
93
101
|
|
|
94
102
|
debug: bool = False
|
|
95
103
|
version: str = version
|
|
96
104
|
session_key: SecretStr = SecretStr("ct-!secret-must-change-me")
|
|
97
105
|
|
|
106
|
+
# Database and Cache URLs
|
|
107
|
+
mongodb_url: MongoDsn = MongoDsn("mongodb://localhost:27017")
|
|
108
|
+
redis_url: RedisDsn = RedisDsn("redis://localhost:6379")
|
|
109
|
+
|
|
98
110
|
aws_access_key_id: SecretStr | None = None
|
|
99
111
|
aws_secret_access_key: SecretStr | None = None
|
|
100
112
|
|
|
@@ -125,4 +137,8 @@ class CoreConfiguration(BaseSettings):
|
|
|
125
137
|
)
|
|
126
138
|
|
|
127
139
|
|
|
128
|
-
settings = CoreConfiguration(
|
|
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
vibetuner/frontend/__init__.py
CHANGED
|
@@ -21,8 +21,13 @@ def register_router(router: APIRouter) -> None:
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
try:
|
|
24
|
-
import app.frontend.oauth as _app_oauth # noqa: F401
|
|
25
|
-
import app.frontend.routes as _app_routes # noqa: F401
|
|
24
|
+
import app.frontend.oauth as _app_oauth # noqa: F401 # type: ignore[unresolved-import]
|
|
25
|
+
import app.frontend.routes as _app_routes # noqa: F401 # type: ignore[unresolved-import]
|
|
26
|
+
|
|
27
|
+
# Register OAuth routes after providers are registered
|
|
28
|
+
from .routes.auth import register_oauth_routes
|
|
29
|
+
|
|
30
|
+
register_oauth_routes()
|
|
26
31
|
except (ImportError, ModuleNotFoundError):
|
|
27
32
|
pass
|
|
28
33
|
|
vibetuner/frontend/lifespan.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
vibetuner/frontend/middleware.py
CHANGED
|
@@ -13,12 +13,12 @@ from starlette_babel import (
|
|
|
13
13
|
LocaleMiddleware,
|
|
14
14
|
get_translator,
|
|
15
15
|
)
|
|
16
|
-
from starlette_htmx.middleware import HtmxMiddleware
|
|
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
|
|
|
@@ -66,7 +66,7 @@ def user_preference_selector(conn: HTTPConnection) -> str | None:
|
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
shared_translator = get_translator()
|
|
69
|
-
if locales_path.exists() and locales_path.is_dir():
|
|
69
|
+
if locales_path is not None and locales_path.exists() and locales_path.is_dir():
|
|
70
70
|
# Load translations from the locales directory
|
|
71
71
|
shared_translator.load_from_directories([locales_path])
|
|
72
72
|
|
|
@@ -135,16 +135,22 @@ async def email_verify(
|
|
|
135
135
|
return next or get_homepage_url(request)
|
|
136
136
|
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
138
|
+
def register_oauth_routes() -> None:
|
|
139
|
+
"""Register OAuth provider routes dynamically.
|
|
140
|
+
|
|
141
|
+
This must be called after OAuth providers are registered to ensure
|
|
142
|
+
routes are created for all configured providers.
|
|
143
|
+
"""
|
|
144
|
+
for provider in get_oauth_providers():
|
|
145
|
+
router.get(
|
|
146
|
+
f"/provider/{provider}",
|
|
147
|
+
response_class=RedirectResponse,
|
|
148
|
+
name=f"auth_with_{provider}",
|
|
149
|
+
response_model=None,
|
|
150
|
+
)(_create_auth_handler(provider))
|
|
151
|
+
|
|
152
|
+
router.get(
|
|
153
|
+
f"/login/provider/{provider}",
|
|
154
|
+
name=f"login_with_{provider}",
|
|
155
|
+
response_model=None,
|
|
156
|
+
)(_create_auth_login_handler(provider))
|
|
@@ -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
|
|
|
@@ -22,6 +22,10 @@ def health_ping():
|
|
|
22
22
|
@router.get("/id")
|
|
23
23
|
def health_instance_id():
|
|
24
24
|
"""Instance identification endpoint for distinguishing app instances"""
|
|
25
|
+
if root_path is None:
|
|
26
|
+
raise RuntimeError(
|
|
27
|
+
"Project root not detected. Cannot provide instance information."
|
|
28
|
+
)
|
|
25
29
|
return {
|
|
26
30
|
"app": settings.project.project_slug,
|
|
27
31
|
"port": int(os.environ.get("PORT", 8000)),
|
|
@@ -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
|
@@ -9,7 +9,7 @@ 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.
|
|
12
|
+
host=str(settings.mongodb_url),
|
|
13
13
|
compressors=["zstd"],
|
|
14
14
|
)
|
|
15
15
|
|