mdb-engine 0.2.1__py3-none-any.whl → 0.2.3__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.
- mdb_engine/auth/audit.py +40 -40
- mdb_engine/auth/base.py +3 -3
- mdb_engine/auth/casbin_factory.py +6 -6
- mdb_engine/auth/config_defaults.py +5 -5
- mdb_engine/auth/config_helpers.py +12 -12
- mdb_engine/auth/cookie_utils.py +9 -9
- mdb_engine/auth/csrf.py +9 -8
- mdb_engine/auth/decorators.py +7 -6
- mdb_engine/auth/dependencies.py +22 -21
- mdb_engine/auth/integration.py +9 -9
- mdb_engine/auth/jwt.py +9 -9
- mdb_engine/auth/middleware.py +4 -3
- mdb_engine/auth/oso_factory.py +6 -6
- mdb_engine/auth/provider.py +4 -4
- mdb_engine/auth/rate_limiter.py +12 -11
- mdb_engine/auth/restrictions.py +16 -15
- mdb_engine/auth/session_manager.py +11 -13
- mdb_engine/auth/shared_middleware.py +16 -15
- mdb_engine/auth/shared_users.py +20 -20
- mdb_engine/auth/token_lifecycle.py +10 -12
- mdb_engine/auth/token_store.py +4 -5
- mdb_engine/auth/users.py +51 -52
- mdb_engine/auth/utils.py +29 -33
- mdb_engine/cli/commands/generate.py +6 -6
- mdb_engine/cli/utils.py +4 -4
- mdb_engine/config.py +6 -7
- mdb_engine/core/app_registration.py +12 -12
- mdb_engine/core/app_secrets.py +1 -2
- mdb_engine/core/connection.py +3 -4
- mdb_engine/core/encryption.py +1 -2
- mdb_engine/core/engine.py +43 -44
- mdb_engine/core/manifest.py +59 -58
- mdb_engine/core/ray_integration.py +10 -9
- mdb_engine/core/seeding.py +3 -3
- mdb_engine/core/service_initialization.py +10 -9
- mdb_engine/core/types.py +40 -40
- mdb_engine/database/abstraction.py +15 -16
- mdb_engine/database/connection.py +40 -12
- mdb_engine/database/query_validator.py +8 -8
- mdb_engine/database/resource_limiter.py +7 -7
- mdb_engine/database/scoped_wrapper.py +51 -58
- mdb_engine/dependencies.py +14 -13
- mdb_engine/di/container.py +12 -13
- mdb_engine/di/providers.py +14 -13
- mdb_engine/di/scopes.py +5 -5
- mdb_engine/embeddings/dependencies.py +2 -2
- mdb_engine/embeddings/service.py +31 -43
- mdb_engine/exceptions.py +20 -20
- mdb_engine/indexes/helpers.py +11 -11
- mdb_engine/indexes/manager.py +9 -9
- mdb_engine/memory/service.py +30 -30
- mdb_engine/observability/health.py +10 -9
- mdb_engine/observability/logging.py +10 -10
- mdb_engine/observability/metrics.py +8 -7
- mdb_engine/repositories/base.py +25 -25
- mdb_engine/repositories/mongo.py +17 -17
- mdb_engine/repositories/unit_of_work.py +6 -6
- mdb_engine/routing/websockets.py +19 -18
- {mdb_engine-0.2.1.dist-info → mdb_engine-0.2.3.dist-info}/METADATA +8 -8
- mdb_engine-0.2.3.dist-info/RECORD +96 -0
- mdb_engine-0.2.1.dist-info/RECORD +0 -96
- {mdb_engine-0.2.1.dist-info → mdb_engine-0.2.3.dist-info}/WHEEL +0 -0
- {mdb_engine-0.2.1.dist-info → mdb_engine-0.2.3.dist-info}/entry_points.txt +0 -0
- {mdb_engine-0.2.1.dist-info → mdb_engine-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {mdb_engine-0.2.1.dist-info → mdb_engine-0.2.3.dist-info}/top_level.txt +0 -0
mdb_engine/auth/utils.py
CHANGED
|
@@ -11,7 +11,7 @@ import logging
|
|
|
11
11
|
import re
|
|
12
12
|
import uuid
|
|
13
13
|
from datetime import datetime
|
|
14
|
-
from typing import Any
|
|
14
|
+
from typing import Any
|
|
15
15
|
|
|
16
16
|
import bcrypt
|
|
17
17
|
from fastapi import Request, Response
|
|
@@ -43,7 +43,7 @@ def _detect_browser(user_agent: str) -> str:
|
|
|
43
43
|
return "unknown"
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def _detect_os_and_device_type(user_agent: str) ->
|
|
46
|
+
def _detect_os_and_device_type(user_agent: str) -> tuple[str, str]:
|
|
47
47
|
"""Detect OS and device type from user agent string."""
|
|
48
48
|
if not user_agent:
|
|
49
49
|
return "unknown", "desktop"
|
|
@@ -64,7 +64,7 @@ def _detect_os_and_device_type(user_agent: str) -> Tuple[str, str]:
|
|
|
64
64
|
return "unknown", "desktop"
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
def get_device_info(request: Request) ->
|
|
67
|
+
def get_device_info(request: Request) -> dict[str, Any]:
|
|
68
68
|
"""
|
|
69
69
|
Extract device information from request.
|
|
70
70
|
|
|
@@ -236,15 +236,15 @@ async def check_password_breach(password: str) -> bool:
|
|
|
236
236
|
|
|
237
237
|
def validate_password_strength(
|
|
238
238
|
password: str,
|
|
239
|
-
min_length:
|
|
240
|
-
require_uppercase:
|
|
241
|
-
require_lowercase:
|
|
242
|
-
require_numbers:
|
|
243
|
-
require_special:
|
|
244
|
-
min_entropy_bits:
|
|
245
|
-
check_common_passwords:
|
|
246
|
-
config:
|
|
247
|
-
) ->
|
|
239
|
+
min_length: int | None = None,
|
|
240
|
+
require_uppercase: bool | None = None,
|
|
241
|
+
require_lowercase: bool | None = None,
|
|
242
|
+
require_numbers: bool | None = None,
|
|
243
|
+
require_special: bool | None = None,
|
|
244
|
+
min_entropy_bits: int | None = None,
|
|
245
|
+
check_common_passwords: bool | None = None,
|
|
246
|
+
config: dict[str, Any] | None = None,
|
|
247
|
+
) -> tuple[bool, list[str]]:
|
|
248
248
|
"""
|
|
249
249
|
Validate password strength with configurable rules.
|
|
250
250
|
|
|
@@ -338,9 +338,9 @@ def validate_password_strength(
|
|
|
338
338
|
|
|
339
339
|
async def validate_password_strength_async(
|
|
340
340
|
password: str,
|
|
341
|
-
config:
|
|
342
|
-
check_breaches:
|
|
343
|
-
) ->
|
|
341
|
+
config: dict[str, Any] | None = None,
|
|
342
|
+
check_breaches: bool | None = None,
|
|
343
|
+
) -> tuple[bool, list[str]]:
|
|
344
344
|
"""
|
|
345
345
|
Async version of validate_password_strength with breach checking.
|
|
346
346
|
|
|
@@ -404,10 +404,10 @@ async def login_user(
|
|
|
404
404
|
email: str,
|
|
405
405
|
password: str,
|
|
406
406
|
db,
|
|
407
|
-
config:
|
|
407
|
+
config: dict[str, Any] | None = None,
|
|
408
408
|
remember_me: bool = False,
|
|
409
|
-
redirect_url:
|
|
410
|
-
) ->
|
|
409
|
+
redirect_url: str | None = None,
|
|
410
|
+
) -> dict[str, Any]:
|
|
411
411
|
"""
|
|
412
412
|
Handle user login with automatic token generation and cookie setting.
|
|
413
413
|
|
|
@@ -571,8 +571,8 @@ def _validate_email_format(email: str) -> bool:
|
|
|
571
571
|
|
|
572
572
|
|
|
573
573
|
def _get_password_policy_from_config(
|
|
574
|
-
request: Request, config:
|
|
575
|
-
) ->
|
|
574
|
+
request: Request, config: dict[str, Any] | None
|
|
575
|
+
) -> dict[str, Any] | None:
|
|
576
576
|
"""Get password policy from config or request."""
|
|
577
577
|
if config:
|
|
578
578
|
security = config.get("security", {})
|
|
@@ -585,8 +585,8 @@ def _get_password_policy_from_config(
|
|
|
585
585
|
|
|
586
586
|
|
|
587
587
|
async def _create_user_document(
|
|
588
|
-
email: str, password: str, extra_data:
|
|
589
|
-
) ->
|
|
588
|
+
email: str, password: str, extra_data: dict[str, Any] | None
|
|
589
|
+
) -> dict[str, Any]:
|
|
590
590
|
"""Create user document with hashed password."""
|
|
591
591
|
password_hash = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())
|
|
592
592
|
user_doc = {
|
|
@@ -600,9 +600,7 @@ async def _create_user_document(
|
|
|
600
600
|
return user_doc
|
|
601
601
|
|
|
602
602
|
|
|
603
|
-
def _create_registration_response(
|
|
604
|
-
user_doc: Dict[str, Any], redirect_url: Optional[str]
|
|
605
|
-
) -> Response:
|
|
603
|
+
def _create_registration_response(user_doc: dict[str, Any], redirect_url: str | None) -> Response:
|
|
606
604
|
"""Create response for registration."""
|
|
607
605
|
if redirect_url:
|
|
608
606
|
return RedirectResponse(url=redirect_url, status_code=302)
|
|
@@ -622,10 +620,10 @@ async def register_user(
|
|
|
622
620
|
email: str,
|
|
623
621
|
password: str,
|
|
624
622
|
db,
|
|
625
|
-
config:
|
|
626
|
-
extra_data:
|
|
627
|
-
redirect_url:
|
|
628
|
-
) ->
|
|
623
|
+
config: dict[str, Any] | None = None,
|
|
624
|
+
extra_data: dict[str, Any] | None = None,
|
|
625
|
+
redirect_url: str | None = None,
|
|
626
|
+
) -> dict[str, Any]:
|
|
629
627
|
"""
|
|
630
628
|
Handle user registration with automatic token generation.
|
|
631
629
|
|
|
@@ -710,7 +708,7 @@ async def register_user(
|
|
|
710
708
|
return {"success": False, "error": "Registration failed. Please try again."}
|
|
711
709
|
|
|
712
710
|
|
|
713
|
-
async def _get_user_id_from_request(request: Request, user_id:
|
|
711
|
+
async def _get_user_id_from_request(request: Request, user_id: str | None) -> str | None:
|
|
714
712
|
"""Extract user_id from request if not provided."""
|
|
715
713
|
if user_id:
|
|
716
714
|
return user_id
|
|
@@ -773,9 +771,7 @@ async def _revoke_session(request: Request) -> None:
|
|
|
773
771
|
await session_mgr.revoke_session_by_refresh_token(refresh_jti)
|
|
774
772
|
|
|
775
773
|
|
|
776
|
-
async def logout_user(
|
|
777
|
-
request: Request, response: Response, user_id: Optional[str] = None
|
|
778
|
-
) -> Response:
|
|
774
|
+
async def logout_user(request: Request, response: Response, user_id: str | None = None) -> Response:
|
|
779
775
|
"""
|
|
780
776
|
Handle user logout with token revocation and cookie clearing.
|
|
781
777
|
|
|
@@ -17,7 +17,7 @@ This module is part of MDB_ENGINE - MongoDB Engine.
|
|
|
17
17
|
|
|
18
18
|
import json
|
|
19
19
|
from pathlib import Path
|
|
20
|
-
from typing import Any
|
|
20
|
+
from typing import Any
|
|
21
21
|
|
|
22
22
|
import click
|
|
23
23
|
|
|
@@ -210,7 +210,7 @@ class AppGenerator:
|
|
|
210
210
|
output_dir: Path = Path("."),
|
|
211
211
|
multi_site: bool = False,
|
|
212
212
|
enable_ray: bool = False,
|
|
213
|
-
read_scopes:
|
|
213
|
+
read_scopes: list[str] | None = None,
|
|
214
214
|
) -> Path:
|
|
215
215
|
"""
|
|
216
216
|
Generate a new app with proper structure.
|
|
@@ -283,10 +283,10 @@ class AppGenerator:
|
|
|
283
283
|
description: str,
|
|
284
284
|
multi_site: bool,
|
|
285
285
|
enable_ray: bool,
|
|
286
|
-
read_scopes:
|
|
287
|
-
) ->
|
|
286
|
+
read_scopes: list[str],
|
|
287
|
+
) -> dict[str, Any]:
|
|
288
288
|
"""Generate manifest.json content."""
|
|
289
|
-
manifest:
|
|
289
|
+
manifest: dict[str, Any] = {
|
|
290
290
|
"schema_version": CURRENT_SCHEMA_VERSION,
|
|
291
291
|
"slug": app_slug,
|
|
292
292
|
"name": app_name,
|
|
@@ -476,7 +476,7 @@ def generate_manifest(
|
|
|
476
476
|
)
|
|
477
477
|
|
|
478
478
|
# Generate template manifest
|
|
479
|
-
manifest:
|
|
479
|
+
manifest: dict[str, Any] = {
|
|
480
480
|
"schema_version": CURRENT_SCHEMA_VERSION,
|
|
481
481
|
"slug": slug,
|
|
482
482
|
"name": name,
|
mdb_engine/cli/utils.py
CHANGED
|
@@ -8,12 +8,12 @@ This module is part of MDB_ENGINE - MongoDB Engine.
|
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
11
|
+
from typing import Any
|
|
12
12
|
|
|
13
13
|
import click
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def load_manifest_file(file_path: Path) ->
|
|
16
|
+
def load_manifest_file(file_path: Path) -> dict[str, Any]:
|
|
17
17
|
"""
|
|
18
18
|
Load a manifest JSON file.
|
|
19
19
|
|
|
@@ -36,7 +36,7 @@ def load_manifest_file(file_path: Path) -> Dict[str, Any]:
|
|
|
36
36
|
raise click.ClickException(f"Invalid JSON in manifest file: {e}") from e
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def save_manifest_file(file_path: Path, manifest:
|
|
39
|
+
def save_manifest_file(file_path: Path, manifest: dict[str, Any]) -> None:
|
|
40
40
|
"""
|
|
41
41
|
Save a manifest dictionary to a JSON file.
|
|
42
42
|
|
|
@@ -54,7 +54,7 @@ def save_manifest_file(file_path: Path, manifest: Dict[str, Any]) -> None:
|
|
|
54
54
|
raise click.ClickException(f"Failed to write manifest file: {e}") from e
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def format_manifest_output(manifest:
|
|
57
|
+
def format_manifest_output(manifest: dict[str, Any], format_type: str) -> str:
|
|
58
58
|
"""
|
|
59
59
|
Format manifest for output.
|
|
60
60
|
|
mdb_engine/config.py
CHANGED
|
@@ -7,7 +7,6 @@ with direct parameters as before.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import os
|
|
10
|
-
from typing import Optional
|
|
11
10
|
|
|
12
11
|
try:
|
|
13
12
|
from pydantic import BaseSettings, Field
|
|
@@ -46,12 +45,12 @@ class EngineConfig:
|
|
|
46
45
|
|
|
47
46
|
def __init__(
|
|
48
47
|
self,
|
|
49
|
-
mongo_uri:
|
|
50
|
-
db_name:
|
|
51
|
-
max_pool_size:
|
|
52
|
-
min_pool_size:
|
|
53
|
-
server_selection_timeout_ms:
|
|
54
|
-
authz_cache_ttl:
|
|
48
|
+
mongo_uri: str | None = None,
|
|
49
|
+
db_name: str | None = None,
|
|
50
|
+
max_pool_size: int | None = None,
|
|
51
|
+
min_pool_size: int | None = None,
|
|
52
|
+
server_selection_timeout_ms: int | None = None,
|
|
53
|
+
authz_cache_ttl: int | None = None,
|
|
55
54
|
):
|
|
56
55
|
"""
|
|
57
56
|
Initialize configuration.
|
|
@@ -10,8 +10,9 @@ This module is part of MDB_ENGINE - MongoDB Engine.
|
|
|
10
10
|
import asyncio
|
|
11
11
|
import logging
|
|
12
12
|
import time
|
|
13
|
+
from collections.abc import Callable
|
|
13
14
|
from pathlib import Path
|
|
14
|
-
from typing import TYPE_CHECKING, Any,
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
15
16
|
|
|
16
17
|
from jsonschema import SchemaError
|
|
17
18
|
from jsonschema import ValidationError as JsonSchemaValidationError
|
|
@@ -58,11 +59,11 @@ class AppRegistrationManager:
|
|
|
58
59
|
self._mongo_db = mongo_db
|
|
59
60
|
self.manifest_validator = manifest_validator
|
|
60
61
|
self.manifest_parser = manifest_parser
|
|
61
|
-
self._apps:
|
|
62
|
+
self._apps: dict[str, dict[str, Any]] = {}
|
|
62
63
|
|
|
63
64
|
async def validate_manifest(
|
|
64
65
|
self, manifest: "ManifestDict"
|
|
65
|
-
) ->
|
|
66
|
+
) -> tuple[bool, str | None, list[str] | None]:
|
|
66
67
|
"""
|
|
67
68
|
Validate a manifest against the schema.
|
|
68
69
|
|
|
@@ -115,13 +116,12 @@ class AppRegistrationManager:
|
|
|
115
116
|
async def register_app(
|
|
116
117
|
self,
|
|
117
118
|
manifest: "ManifestDict",
|
|
118
|
-
create_indexes_callback:
|
|
119
|
-
seed_data_callback:
|
|
120
|
-
initialize_memory_callback:
|
|
121
|
-
register_websockets_callback:
|
|
122
|
-
setup_observability_callback:
|
|
123
|
-
|
|
124
|
-
] = None,
|
|
119
|
+
create_indexes_callback: Callable[[str, "ManifestDict"], Any] | None = None,
|
|
120
|
+
seed_data_callback: Callable[[str, dict[str, list[dict[str, Any]]]], Any] | None = None,
|
|
121
|
+
initialize_memory_callback: Callable[[str, dict[str, Any]], Any] | None = None,
|
|
122
|
+
register_websockets_callback: Callable[[str, dict[str, Any]], Any] | None = None,
|
|
123
|
+
setup_observability_callback: Callable[[str, "ManifestDict", dict[str, Any]], Any]
|
|
124
|
+
| None = None,
|
|
125
125
|
) -> bool:
|
|
126
126
|
"""
|
|
127
127
|
Register an app from its manifest.
|
|
@@ -142,7 +142,7 @@ class AppRegistrationManager:
|
|
|
142
142
|
"""
|
|
143
143
|
start_time = time.time()
|
|
144
144
|
|
|
145
|
-
slug:
|
|
145
|
+
slug: str | None = manifest.get("slug")
|
|
146
146
|
if not slug:
|
|
147
147
|
contextual_logger.error(
|
|
148
148
|
"Cannot register app: missing 'slug' in manifest",
|
|
@@ -359,7 +359,7 @@ class AppRegistrationManager:
|
|
|
359
359
|
"""
|
|
360
360
|
return self._apps.get(slug)
|
|
361
361
|
|
|
362
|
-
def list_apps(self) ->
|
|
362
|
+
def list_apps(self) -> list[str]:
|
|
363
363
|
"""
|
|
364
364
|
List all registered app slugs.
|
|
365
365
|
|
mdb_engine/core/app_secrets.py
CHANGED
|
@@ -13,7 +13,6 @@ import base64
|
|
|
13
13
|
import logging
|
|
14
14
|
import secrets
|
|
15
15
|
from datetime import datetime
|
|
16
|
-
from typing import Optional
|
|
17
16
|
|
|
18
17
|
from motor.motor_asyncio import AsyncIOMotorDatabase
|
|
19
18
|
from pymongo.errors import OperationFailure, PyMongoError
|
|
@@ -188,7 +187,7 @@ class AppSecretsManager:
|
|
|
188
187
|
logger.warning(f"Secret verification failed for app '{app_slug}'")
|
|
189
188
|
return result
|
|
190
189
|
|
|
191
|
-
async def get_app_secret(self, app_slug: str) ->
|
|
190
|
+
async def get_app_secret(self, app_slug: str) -> str | None:
|
|
192
191
|
"""
|
|
193
192
|
Get decrypted app secret (for rotation purposes only).
|
|
194
193
|
|
mdb_engine/core/connection.py
CHANGED
|
@@ -9,7 +9,6 @@ This module is part of MDB_ENGINE - MongoDB Engine.
|
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
11
|
import time
|
|
12
|
-
from typing import Optional
|
|
13
12
|
|
|
14
13
|
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
|
|
15
14
|
from pymongo.errors import ConnectionFailure, ServerSelectionTimeoutError
|
|
@@ -57,8 +56,8 @@ class ConnectionManager:
|
|
|
57
56
|
self.min_pool_size = min_pool_size
|
|
58
57
|
|
|
59
58
|
# Connection state
|
|
60
|
-
self._mongo_client:
|
|
61
|
-
self._mongo_db:
|
|
59
|
+
self._mongo_client: AsyncIOMotorClient | None = None
|
|
60
|
+
self._mongo_db: AsyncIOMotorDatabase | None = None
|
|
62
61
|
self._initialized: bool = False
|
|
63
62
|
|
|
64
63
|
async def initialize(self) -> None:
|
|
@@ -242,7 +241,7 @@ class ConnectionManager:
|
|
|
242
241
|
self._mongo_db = None
|
|
243
242
|
|
|
244
243
|
@mongo_db.setter
|
|
245
|
-
def mongo_db(self, value:
|
|
244
|
+
def mongo_db(self, value: AsyncIOMotorDatabase | None) -> None:
|
|
246
245
|
"""Allow setting mongo_db property for testing purposes."""
|
|
247
246
|
self._mongo_db = value
|
|
248
247
|
|
mdb_engine/core/encryption.py
CHANGED
|
@@ -19,7 +19,6 @@ import base64
|
|
|
19
19
|
import logging
|
|
20
20
|
import os
|
|
21
21
|
import secrets
|
|
22
|
-
from typing import Tuple
|
|
23
22
|
|
|
24
23
|
import cryptography.exceptions
|
|
25
24
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
@@ -121,7 +120,7 @@ class EnvelopeEncryptionService:
|
|
|
121
120
|
"""
|
|
122
121
|
return secrets.token_bytes(AES_KEY_SIZE)
|
|
123
122
|
|
|
124
|
-
def encrypt_secret(self, secret: str, master_key: bytes | None = None) ->
|
|
123
|
+
def encrypt_secret(self, secret: str, master_key: bytes | None = None) -> tuple[bytes, bytes]:
|
|
125
124
|
"""
|
|
126
125
|
Encrypt a secret using envelope encryption.
|
|
127
126
|
|
mdb_engine/core/engine.py
CHANGED
|
@@ -28,9 +28,10 @@ Usage:
|
|
|
28
28
|
import logging
|
|
29
29
|
import os
|
|
30
30
|
import secrets
|
|
31
|
+
from collections.abc import Awaitable, Callable
|
|
31
32
|
from contextlib import asynccontextmanager
|
|
32
33
|
from pathlib import Path
|
|
33
|
-
from typing import TYPE_CHECKING, Any,
|
|
34
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
34
35
|
|
|
35
36
|
from motor.motor_asyncio import AsyncIOMotorClient
|
|
36
37
|
from pymongo.errors import PyMongoError
|
|
@@ -94,7 +95,7 @@ class MongoDBEngine:
|
|
|
94
95
|
self,
|
|
95
96
|
mongo_uri: str,
|
|
96
97
|
db_name: str,
|
|
97
|
-
manifests_dir:
|
|
98
|
+
manifests_dir: Path | None = None,
|
|
98
99
|
authz_provider: Optional["AuthorizationProvider"] = None,
|
|
99
100
|
max_pool_size: int = DEFAULT_MAX_POOL_SIZE,
|
|
100
101
|
min_pool_size: int = DEFAULT_MIN_POOL_SIZE,
|
|
@@ -142,17 +143,17 @@ class MongoDBEngine:
|
|
|
142
143
|
self.manifest_parser = ManifestParser()
|
|
143
144
|
|
|
144
145
|
# Initialize managers (will be set up after connection is established)
|
|
145
|
-
self._app_registration_manager:
|
|
146
|
-
self._index_manager:
|
|
147
|
-
self._service_initializer:
|
|
148
|
-
self._encryption_service:
|
|
149
|
-
self._app_secrets_manager:
|
|
146
|
+
self._app_registration_manager: AppRegistrationManager | None = None
|
|
147
|
+
self._index_manager: IndexManager | None = None
|
|
148
|
+
self._service_initializer: ServiceInitializer | None = None
|
|
149
|
+
self._encryption_service: EnvelopeEncryptionService | None = None
|
|
150
|
+
self._app_secrets_manager: AppSecretsManager | None = None
|
|
150
151
|
|
|
151
152
|
# Store app read_scopes mapping for validation
|
|
152
|
-
self._app_read_scopes:
|
|
153
|
+
self._app_read_scopes: dict[str, list[str]] = {}
|
|
153
154
|
|
|
154
155
|
# Store app token cache for auto-retrieval
|
|
155
|
-
self._app_token_cache:
|
|
156
|
+
self._app_token_cache: dict[str, str] = {}
|
|
156
157
|
|
|
157
158
|
async def initialize(self) -> None:
|
|
158
159
|
"""
|
|
@@ -300,9 +301,9 @@ class MongoDBEngine:
|
|
|
300
301
|
def get_scoped_db(
|
|
301
302
|
self,
|
|
302
303
|
app_slug: str,
|
|
303
|
-
app_token:
|
|
304
|
-
read_scopes:
|
|
305
|
-
write_scope:
|
|
304
|
+
app_token: str | None = None,
|
|
305
|
+
read_scopes: list[str] | None = None,
|
|
306
|
+
write_scope: str | None = None,
|
|
306
307
|
auto_index: bool = True,
|
|
307
308
|
) -> ScopedMongoWrapper:
|
|
308
309
|
"""
|
|
@@ -435,9 +436,9 @@ class MongoDBEngine:
|
|
|
435
436
|
async def get_scoped_db_async(
|
|
436
437
|
self,
|
|
437
438
|
app_slug: str,
|
|
438
|
-
app_token:
|
|
439
|
-
read_scopes:
|
|
440
|
-
write_scope:
|
|
439
|
+
app_token: str | None = None,
|
|
440
|
+
read_scopes: list[str] | None = None,
|
|
441
|
+
write_scope: str | None = None,
|
|
441
442
|
auto_index: bool = True,
|
|
442
443
|
) -> ScopedMongoWrapper:
|
|
443
444
|
"""
|
|
@@ -540,7 +541,7 @@ class MongoDBEngine:
|
|
|
540
541
|
|
|
541
542
|
async def validate_manifest(
|
|
542
543
|
self, manifest: "ManifestDict"
|
|
543
|
-
) ->
|
|
544
|
+
) -> tuple[bool, str | None, list[str] | None]:
|
|
544
545
|
"""
|
|
545
546
|
Validate a manifest against the schema.
|
|
546
547
|
|
|
@@ -604,16 +605,16 @@ class MongoDBEngine:
|
|
|
604
605
|
if self._index_manager and create_indexes:
|
|
605
606
|
await self._index_manager.create_app_indexes(slug, manifest)
|
|
606
607
|
|
|
607
|
-
async def seed_data_callback(slug: str, initial_data:
|
|
608
|
+
async def seed_data_callback(slug: str, initial_data: dict[str, Any]) -> None:
|
|
608
609
|
if self._service_initializer:
|
|
609
610
|
await self._service_initializer.seed_initial_data(slug, initial_data)
|
|
610
611
|
|
|
611
|
-
async def initialize_memory_callback(slug: str, memory_config:
|
|
612
|
+
async def initialize_memory_callback(slug: str, memory_config: dict[str, Any]) -> None:
|
|
612
613
|
if self._service_initializer:
|
|
613
614
|
await self._service_initializer.initialize_memory_service(slug, memory_config)
|
|
614
615
|
|
|
615
616
|
async def register_websockets_callback(
|
|
616
|
-
slug: str, websockets_config:
|
|
617
|
+
slug: str, websockets_config: dict[str, Any]
|
|
617
618
|
) -> None:
|
|
618
619
|
if self._service_initializer:
|
|
619
620
|
await self._service_initializer.register_websockets(slug, websockets_config)
|
|
@@ -621,7 +622,7 @@ class MongoDBEngine:
|
|
|
621
622
|
async def setup_observability_callback(
|
|
622
623
|
slug: str,
|
|
623
624
|
manifest: "ManifestDict",
|
|
624
|
-
observability_config:
|
|
625
|
+
observability_config: dict[str, Any],
|
|
625
626
|
) -> None:
|
|
626
627
|
if self._service_initializer:
|
|
627
628
|
await self._service_initializer.setup_observability(
|
|
@@ -665,7 +666,7 @@ class MongoDBEngine:
|
|
|
665
666
|
|
|
666
667
|
return result
|
|
667
668
|
|
|
668
|
-
def get_websocket_config(self, slug: str) ->
|
|
669
|
+
def get_websocket_config(self, slug: str) -> dict[str, Any] | None:
|
|
669
670
|
"""
|
|
670
671
|
Get WebSocket configuration for an app.
|
|
671
672
|
|
|
@@ -851,7 +852,7 @@ class MongoDBEngine:
|
|
|
851
852
|
raise RuntimeError("MongoDBEngine not initialized. Call initialize() first.")
|
|
852
853
|
return await self._app_registration_manager.get_manifest(slug)
|
|
853
854
|
|
|
854
|
-
def get_memory_service(self, slug: str) ->
|
|
855
|
+
def get_memory_service(self, slug: str) -> Any | None:
|
|
855
856
|
"""
|
|
856
857
|
Get Mem0 memory service for an app.
|
|
857
858
|
|
|
@@ -875,7 +876,7 @@ class MongoDBEngine:
|
|
|
875
876
|
return self._service_initializer.get_memory_service(slug)
|
|
876
877
|
return None
|
|
877
878
|
|
|
878
|
-
def get_embedding_service(self, slug: str) ->
|
|
879
|
+
def get_embedding_service(self, slug: str) -> Any | None:
|
|
879
880
|
"""
|
|
880
881
|
Get EmbeddingService for an app.
|
|
881
882
|
|
|
@@ -900,7 +901,7 @@ class MongoDBEngine:
|
|
|
900
901
|
return get_embedding_service_for_app(slug, self)
|
|
901
902
|
|
|
902
903
|
@property
|
|
903
|
-
def _apps(self) ->
|
|
904
|
+
def _apps(self) -> dict[str, Any]:
|
|
904
905
|
"""
|
|
905
906
|
Get the apps dictionary (for backward compatibility with tests).
|
|
906
907
|
|
|
@@ -914,7 +915,7 @@ class MongoDBEngine:
|
|
|
914
915
|
raise RuntimeError("MongoDBEngine not initialized. Call initialize() first.")
|
|
915
916
|
return self._app_registration_manager._apps
|
|
916
917
|
|
|
917
|
-
def list_apps(self) ->
|
|
918
|
+
def list_apps(self) -> list[str]:
|
|
918
919
|
"""
|
|
919
920
|
List all registered app slugs.
|
|
920
921
|
|
|
@@ -958,9 +959,9 @@ class MongoDBEngine:
|
|
|
958
959
|
|
|
959
960
|
def __exit__(
|
|
960
961
|
self,
|
|
961
|
-
exc_type:
|
|
962
|
-
exc_val:
|
|
963
|
-
exc_tb:
|
|
962
|
+
exc_type: type[BaseException] | None,
|
|
963
|
+
exc_val: BaseException | None,
|
|
964
|
+
exc_tb: Any | None,
|
|
964
965
|
) -> None:
|
|
965
966
|
"""
|
|
966
967
|
Context manager exit (synchronous).
|
|
@@ -991,9 +992,9 @@ class MongoDBEngine:
|
|
|
991
992
|
|
|
992
993
|
async def __aexit__(
|
|
993
994
|
self,
|
|
994
|
-
exc_type:
|
|
995
|
-
exc_val:
|
|
996
|
-
exc_tb:
|
|
995
|
+
exc_type: type[BaseException] | None,
|
|
996
|
+
exc_val: BaseException | None,
|
|
997
|
+
exc_tb: Any | None,
|
|
997
998
|
) -> None:
|
|
998
999
|
"""
|
|
999
1000
|
Async context manager exit.
|
|
@@ -1007,7 +1008,7 @@ class MongoDBEngine:
|
|
|
1007
1008
|
"""
|
|
1008
1009
|
await self.shutdown()
|
|
1009
1010
|
|
|
1010
|
-
async def get_health_status(self) ->
|
|
1011
|
+
async def get_health_status(self) -> dict[str, Any]:
|
|
1011
1012
|
"""
|
|
1012
1013
|
Get health status of the MongoDB Engine.
|
|
1013
1014
|
|
|
@@ -1069,7 +1070,7 @@ class MongoDBEngine:
|
|
|
1069
1070
|
|
|
1070
1071
|
return await health_checker.check_all()
|
|
1071
1072
|
|
|
1072
|
-
def get_metrics(self) ->
|
|
1073
|
+
def get_metrics(self) -> dict[str, Any]:
|
|
1073
1074
|
"""
|
|
1074
1075
|
Get metrics for the MongoDB Engine.
|
|
1075
1076
|
|
|
@@ -1089,13 +1090,11 @@ class MongoDBEngine:
|
|
|
1089
1090
|
self,
|
|
1090
1091
|
slug: str,
|
|
1091
1092
|
manifest: Path,
|
|
1092
|
-
title:
|
|
1093
|
-
on_startup:
|
|
1094
|
-
|
|
1095
|
-
]
|
|
1096
|
-
|
|
1097
|
-
Callable[["FastAPI", "MongoDBEngine", Dict[str, Any]], Awaitable[None]]
|
|
1098
|
-
] = None,
|
|
1093
|
+
title: str | None = None,
|
|
1094
|
+
on_startup: Callable[["FastAPI", "MongoDBEngine", dict[str, Any]], Awaitable[None]]
|
|
1095
|
+
| None = None,
|
|
1096
|
+
on_shutdown: Callable[["FastAPI", "MongoDBEngine", dict[str, Any]], Awaitable[None]]
|
|
1097
|
+
| None = None,
|
|
1099
1098
|
**fastapi_kwargs: Any,
|
|
1100
1099
|
) -> "FastAPI":
|
|
1101
1100
|
"""
|
|
@@ -1170,7 +1169,7 @@ class MongoDBEngine:
|
|
|
1170
1169
|
app_title = title or pre_manifest.get("name", slug)
|
|
1171
1170
|
|
|
1172
1171
|
# State that will be populated during initialization
|
|
1173
|
-
app_manifest:
|
|
1172
|
+
app_manifest: dict[str, Any] = {}
|
|
1174
1173
|
is_multi_site = False
|
|
1175
1174
|
|
|
1176
1175
|
@asynccontextmanager
|
|
@@ -1506,7 +1505,7 @@ class MongoDBEngine:
|
|
|
1506
1505
|
async def _initialize_shared_user_pool(
|
|
1507
1506
|
self,
|
|
1508
1507
|
app: "FastAPI",
|
|
1509
|
-
manifest:
|
|
1508
|
+
manifest: dict[str, Any] | None = None,
|
|
1510
1509
|
) -> None:
|
|
1511
1510
|
"""
|
|
1512
1511
|
Initialize shared user pool, audit log, and set them on app.state.
|
|
@@ -1644,7 +1643,7 @@ class MongoDBEngine:
|
|
|
1644
1643
|
|
|
1645
1644
|
return _lifespan
|
|
1646
1645
|
|
|
1647
|
-
async def auto_retrieve_app_token(self, slug: str) ->
|
|
1646
|
+
async def auto_retrieve_app_token(self, slug: str) -> str | None:
|
|
1648
1647
|
"""
|
|
1649
1648
|
Auto-retrieve app token from environment or database.
|
|
1650
1649
|
|
|
@@ -1697,7 +1696,7 @@ class MongoDBEngine:
|
|
|
1697
1696
|
)
|
|
1698
1697
|
return None
|
|
1699
1698
|
|
|
1700
|
-
def get_app_token(self, slug: str) ->
|
|
1699
|
+
def get_app_token(self, slug: str) -> str | None:
|
|
1701
1700
|
"""
|
|
1702
1701
|
Get cached app token for a slug.
|
|
1703
1702
|
|