mdb-engine 0.1.6__py3-none-any.whl → 0.1.7__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.
Files changed (75) hide show
  1. mdb_engine/__init__.py +38 -6
  2. mdb_engine/auth/README.md +534 -11
  3. mdb_engine/auth/__init__.py +129 -28
  4. mdb_engine/auth/audit.py +592 -0
  5. mdb_engine/auth/casbin_factory.py +10 -14
  6. mdb_engine/auth/config_helpers.py +7 -6
  7. mdb_engine/auth/cookie_utils.py +3 -7
  8. mdb_engine/auth/csrf.py +373 -0
  9. mdb_engine/auth/decorators.py +3 -10
  10. mdb_engine/auth/dependencies.py +37 -45
  11. mdb_engine/auth/helpers.py +3 -3
  12. mdb_engine/auth/integration.py +30 -73
  13. mdb_engine/auth/jwt.py +2 -6
  14. mdb_engine/auth/middleware.py +77 -34
  15. mdb_engine/auth/oso_factory.py +16 -36
  16. mdb_engine/auth/provider.py +17 -38
  17. mdb_engine/auth/rate_limiter.py +504 -0
  18. mdb_engine/auth/restrictions.py +8 -24
  19. mdb_engine/auth/session_manager.py +14 -29
  20. mdb_engine/auth/shared_middleware.py +600 -0
  21. mdb_engine/auth/shared_users.py +759 -0
  22. mdb_engine/auth/token_store.py +14 -28
  23. mdb_engine/auth/users.py +54 -113
  24. mdb_engine/auth/utils.py +213 -15
  25. mdb_engine/cli/commands/generate.py +545 -9
  26. mdb_engine/cli/commands/validate.py +3 -7
  27. mdb_engine/cli/utils.py +3 -3
  28. mdb_engine/config.py +7 -21
  29. mdb_engine/constants.py +65 -0
  30. mdb_engine/core/README.md +117 -6
  31. mdb_engine/core/__init__.py +39 -7
  32. mdb_engine/core/app_registration.py +22 -41
  33. mdb_engine/core/app_secrets.py +290 -0
  34. mdb_engine/core/connection.py +18 -9
  35. mdb_engine/core/encryption.py +223 -0
  36. mdb_engine/core/engine.py +758 -95
  37. mdb_engine/core/index_management.py +12 -16
  38. mdb_engine/core/manifest.py +424 -135
  39. mdb_engine/core/ray_integration.py +435 -0
  40. mdb_engine/core/seeding.py +10 -18
  41. mdb_engine/core/service_initialization.py +12 -23
  42. mdb_engine/core/types.py +2 -5
  43. mdb_engine/database/README.md +112 -16
  44. mdb_engine/database/__init__.py +17 -6
  45. mdb_engine/database/abstraction.py +25 -37
  46. mdb_engine/database/connection.py +11 -18
  47. mdb_engine/database/query_validator.py +367 -0
  48. mdb_engine/database/resource_limiter.py +204 -0
  49. mdb_engine/database/scoped_wrapper.py +713 -196
  50. mdb_engine/embeddings/__init__.py +17 -9
  51. mdb_engine/embeddings/dependencies.py +1 -3
  52. mdb_engine/embeddings/service.py +11 -25
  53. mdb_engine/exceptions.py +92 -0
  54. mdb_engine/indexes/README.md +30 -13
  55. mdb_engine/indexes/__init__.py +1 -0
  56. mdb_engine/indexes/helpers.py +1 -1
  57. mdb_engine/indexes/manager.py +50 -114
  58. mdb_engine/memory/README.md +2 -2
  59. mdb_engine/memory/__init__.py +1 -2
  60. mdb_engine/memory/service.py +30 -87
  61. mdb_engine/observability/README.md +4 -2
  62. mdb_engine/observability/__init__.py +26 -9
  63. mdb_engine/observability/health.py +8 -9
  64. mdb_engine/observability/metrics.py +32 -12
  65. mdb_engine/routing/README.md +1 -1
  66. mdb_engine/routing/__init__.py +1 -3
  67. mdb_engine/routing/websockets.py +25 -60
  68. mdb_engine-0.1.7.dist-info/METADATA +285 -0
  69. mdb_engine-0.1.7.dist-info/RECORD +85 -0
  70. mdb_engine-0.1.6.dist-info/METADATA +0 -213
  71. mdb_engine-0.1.6.dist-info/RECORD +0 -75
  72. {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/WHEEL +0 -0
  73. {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/entry_points.txt +0 -0
  74. {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/licenses/LICENSE +0 -0
  75. {mdb_engine-0.1.6.dist-info → mdb_engine-0.1.7.dist-info}/top_level.txt +0 -0
@@ -72,9 +72,7 @@ class WebSocketConnectionManager:
72
72
  app_slug: App slug for scoping connections (ensures isolation)
73
73
  """
74
74
  self.app_slug = app_slug
75
- self.active_connections: List[WebSocketConnection] = (
76
- []
77
- ) # List of connection metadata
75
+ self.active_connections: List[WebSocketConnection] = [] # List of connection metadata
78
76
  self._lock = asyncio.Lock()
79
77
  logger.debug(f"Initialized WebSocket manager for app: {app_slug}")
80
78
 
@@ -97,10 +95,7 @@ class WebSocketConnectionManager:
97
95
  """
98
96
  # Note: websocket should already be accepted by the endpoint handler
99
97
  # This is just for tracking - don't accept again
100
- if (
101
- hasattr(websocket, "client_state")
102
- and websocket.client_state.name != "CONNECTED"
103
- ):
98
+ if hasattr(websocket, "client_state") and websocket.client_state.name != "CONNECTED":
104
99
  await websocket.accept()
105
100
  connection = WebSocketConnection(
106
101
  websocket=websocket,
@@ -130,9 +125,7 @@ class WebSocketConnectionManager:
130
125
  async def _disconnect():
131
126
  async with self._lock:
132
127
  self.active_connections = [
133
- conn
134
- for conn in self.active_connections
135
- if conn.websocket is not websocket
128
+ conn for conn in self.active_connections if conn.websocket is not websocket
136
129
  ]
137
130
  logger.info(
138
131
  f"WebSocket disconnected for app '{self.app_slug}'. "
@@ -141,9 +134,7 @@ class WebSocketConnectionManager:
141
134
 
142
135
  asyncio.create_task(_disconnect())
143
136
 
144
- async def broadcast(
145
- self, message: Dict[str, Any], filter_by_user: Optional[str] = None
146
- ) -> int:
137
+ async def broadcast(self, message: Dict[str, Any], filter_by_user: Optional[str] = None) -> int:
147
138
  """
148
139
  Broadcast a message to all connected clients for this app.
149
140
 
@@ -276,9 +267,7 @@ _manager_lock = asyncio.Lock()
276
267
 
277
268
  # Global registry of message handlers per app (for listening to client messages)
278
269
  # Note: Registration happens synchronously during app startup, so no lock needed
279
- _message_handlers: Dict[
280
- str, Dict[str, Callable[[Any, Dict[str, Any]], Awaitable[None]]]
281
- ] = {}
270
+ _message_handlers: Dict[str, Dict[str, Callable[[Any, Dict[str, Any]], Awaitable[None]]]] = {}
282
271
 
283
272
 
284
273
  async def get_websocket_manager(app_slug: str) -> WebSocketConnectionManager:
@@ -367,22 +356,16 @@ async def authenticate_websocket(
367
356
  else:
368
357
  logger.info(f"WebSocket query_params is empty for app '{app_slug}'")
369
358
  else:
370
- logger.warning(
371
- f"WebSocket has no query_params attribute for app '{app_slug}'"
372
- )
359
+ logger.warning(f"WebSocket has no query_params attribute for app '{app_slug}'")
373
360
 
374
361
  # If no token in query, try to get from cookies (if available)
375
362
  # Check both ws_token (non-httponly, for JS access) and token (httponly)
376
363
  if not token:
377
364
  if hasattr(websocket, "cookies"):
378
- cookie_token = websocket.cookies.get(
379
- "ws_token"
380
- ) or websocket.cookies.get("token")
365
+ cookie_token = websocket.cookies.get("ws_token") or websocket.cookies.get("token")
381
366
  if cookie_token:
382
367
  token = cookie_token
383
- logger.debug(
384
- f"WebSocket token found in cookies for app '{app_slug}'"
385
- )
368
+ logger.debug(f"WebSocket token found in cookies for app '{app_slug}'")
386
369
  else:
387
370
  logger.debug(f"WebSocket has no cookies attribute for app '{app_slug}'")
388
371
 
@@ -404,6 +387,8 @@ async def authenticate_websocket(
404
387
  return None, None # Signal auth failure
405
388
  return None, None
406
389
 
390
+ import jwt
391
+
407
392
  from ..auth.dependencies import SECRET_KEY
408
393
  from ..auth.jwt import decode_jwt_token
409
394
 
@@ -412,22 +397,16 @@ async def authenticate_websocket(
412
397
  user_id = payload.get("sub") or payload.get("user_id")
413
398
  user_email = payload.get("email")
414
399
 
415
- logger.info(
416
- f"WebSocket authenticated successfully for app '{app_slug}': {user_email}"
417
- )
400
+ logger.info(f"WebSocket authenticated successfully for app '{app_slug}': {user_email}")
418
401
  return user_id, user_email
419
- except Exception as decode_error:
420
- logger.error(
421
- f"JWT decode error for app '{app_slug}': {decode_error}", exc_info=True
422
- )
402
+ except (jwt.ExpiredSignatureError, jwt.InvalidTokenError) as decode_error:
403
+ logger.error(f"JWT decode error for app '{app_slug}': {decode_error}", exc_info=True)
423
404
  raise
424
405
 
425
406
  except WebSocketDisconnect:
426
407
  raise
427
408
  except (ValueError, TypeError, AttributeError, KeyError, RuntimeError) as e:
428
- logger.error(
429
- f"WebSocket authentication failed for app '{app_slug}': {e}", exc_info=True
430
- )
409
+ logger.error(f"WebSocket authentication failed for app '{app_slug}': {e}", exc_info=True)
431
410
  if require_auth:
432
411
  # Don't close before accepting - return error info instead
433
412
  return None, None # Signal auth failure
@@ -469,9 +448,7 @@ def register_message_handler(
469
448
  if app_slug not in _message_handlers:
470
449
  _message_handlers[app_slug] = {}
471
450
  _message_handlers[app_slug][endpoint_name] = handler
472
- logger.info(
473
- f"Registered message handler for app '{app_slug}', endpoint '{endpoint_name}'"
474
- )
451
+ logger.info(f"Registered message handler for app '{app_slug}', endpoint '{endpoint_name}'")
475
452
 
476
453
 
477
454
  def get_message_handler(
@@ -497,7 +474,7 @@ async def _accept_websocket_connection(websocket: Any, app_slug: str) -> None:
497
474
  await websocket.accept()
498
475
  print(f"✅ [WEBSOCKET ACCEPTED] App: '{app_slug}'")
499
476
  logger.info(f"✅ WebSocket accepted for app '{app_slug}'")
500
- except Exception as accept_error:
477
+ except (RuntimeError, ConnectionError, OSError) as accept_error:
501
478
  print(f"❌ [WEBSOCKET ACCEPT FAILED] App: '{app_slug}', Error: {accept_error}")
502
479
  logger.error(
503
480
  f"❌ Failed to accept WebSocket for app '{app_slug}': {accept_error}",
@@ -511,9 +488,7 @@ async def _authenticate_websocket_connection(
511
488
  ) -> tuple:
512
489
  """Authenticate WebSocket connection and return (user_id, user_email)."""
513
490
  try:
514
- user_id, user_email = await authenticate_websocket(
515
- websocket, app_slug, require_auth
516
- )
491
+ user_id, user_email = await authenticate_websocket(websocket, app_slug, require_auth)
517
492
 
518
493
  if require_auth and not user_id:
519
494
  logger.warning(
@@ -522,9 +497,7 @@ async def _authenticate_websocket_connection(
522
497
  try:
523
498
  await websocket.close(code=1008, reason="Authentication required")
524
499
  except (WebSocketDisconnect, RuntimeError, OSError) as e:
525
- logger.debug(
526
- f"WebSocket already closed during auth failure cleanup: {e}"
527
- )
500
+ logger.debug(f"WebSocket already closed during auth failure cleanup: {e}")
528
501
  raise WebSocketDisconnect(code=1008)
529
502
 
530
503
  return user_id, user_email
@@ -547,12 +520,10 @@ async def _authenticate_websocket_connection(
547
520
  exc_info=True,
548
521
  )
549
522
  try:
550
- await websocket.close(
551
- code=1011, reason="Internal server error during authentication"
552
- )
553
- except (WebSocketDisconnect, RuntimeError, OSError) as e:
554
- logger.debug(f"WebSocket already closed during auth error cleanup: {e}")
555
- raise WebSocketDisconnect(code=1011)
523
+ await websocket.close(code=1011, reason="Internal server error during authentication")
524
+ except (WebSocketDisconnect, RuntimeError, OSError) as close_error:
525
+ logger.debug(f"WebSocket already closed during auth error cleanup: {close_error}")
526
+ raise WebSocketDisconnect(code=1011) from None
556
527
 
557
528
 
558
529
  async def _handle_websocket_message(
@@ -656,9 +627,7 @@ def create_websocket_endpoint(
656
627
  file=sys.stderr,
657
628
  flush=True,
658
629
  )
659
- print(
660
- f"🔌 [WEBSOCKET HANDLER CALLED] App: '{app_slug}', Path: {path}", flush=True
661
- )
630
+ print(f"🔌 [WEBSOCKET HANDLER CALLED] App: '{app_slug}', Path: {path}", flush=True)
662
631
  logger.info(f"🔌 [WEBSOCKET HANDLER CALLED] App: '{app_slug}', Path: {path}")
663
632
  connection = None
664
633
  try:
@@ -693,9 +662,7 @@ def create_websocket_endpoint(
693
662
  )
694
663
 
695
664
  # Connect with metadata (websocket already accepted)
696
- connection = await manager.connect(
697
- websocket, user_id=user_id, user_email=user_email
698
- )
665
+ connection = await manager.connect(websocket, user_id=user_id, user_email=user_email)
699
666
 
700
667
  # Send initial connection confirmation
701
668
  await manager.send_to_connection(
@@ -765,9 +732,7 @@ def create_websocket_endpoint(
765
732
  TypeError,
766
733
  AttributeError,
767
734
  ) as e:
768
- logger.error(
769
- f"WebSocket connection error for app '{app_slug}': {e}", exc_info=True
770
- )
735
+ logger.error(f"WebSocket connection error for app '{app_slug}': {e}", exc_info=True)
771
736
  finally:
772
737
  if connection:
773
738
  manager.disconnect(websocket)
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: mdb-engine
3
+ Version: 0.1.7
4
+ Summary: MongoDB Engine
5
+ Home-page: https://github.com/ranfysvalle02/mdb-engine
6
+ Author: Your Name
7
+ Author-email: Your Name <your.email@example.com>
8
+ License: AGPL-3.0
9
+ Project-URL: Homepage, https://github.com/ranfysvalle02/mdb-engine
10
+ Project-URL: Documentation, https://github.com/ranfysvalle02/mdb-engine#readme
11
+ Project-URL: Repository, https://github.com/ranfysvalle02/mdb-engine
12
+ Project-URL: Issues, https://github.com/ranfysvalle02/mdb-engine/issues
13
+ Keywords: mongodb,runtime,engine,database,scoping
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Topic :: Database
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: motor>=3.0.0
28
+ Requires-Dist: pymongo>=4.0.0
29
+ Requires-Dist: fastapi>=0.100.0
30
+ Requires-Dist: pydantic>=2.0.0
31
+ Requires-Dist: pyjwt>=2.8.0
32
+ Requires-Dist: jsonschema>=4.0.0
33
+ Requires-Dist: bcrypt>=4.0.0
34
+ Requires-Dist: cryptography>=41.0.0
35
+ Requires-Dist: mem0ai>=1.0.0
36
+ Requires-Dist: semantic-text-splitter>=0.9.0
37
+ Requires-Dist: numpy<2.0.0,>=1.0.0
38
+ Requires-Dist: openai>=1.0.0
39
+ Requires-Dist: azure-identity>=1.15.0
40
+ Requires-Dist: click>=8.0.0
41
+ Provides-Extra: casbin
42
+ Requires-Dist: casbin>=1.0.0; extra == "casbin"
43
+ Requires-Dist: casbin-motor-adapter>=0.1.0; extra == "casbin"
44
+ Provides-Extra: oso
45
+ Requires-Dist: oso-cloud>=0.1.0; extra == "oso"
46
+ Provides-Extra: llm
47
+ Provides-Extra: test
48
+ Requires-Dist: pytest>=7.4.0; extra == "test"
49
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
50
+ Requires-Dist: pytest-cov>=4.1.0; extra == "test"
51
+ Requires-Dist: pytest-mock>=3.11.0; extra == "test"
52
+ Requires-Dist: pytest-timeout>=2.1.0; extra == "test"
53
+ Requires-Dist: testcontainers>=3.7.0; extra == "test"
54
+ Provides-Extra: dev
55
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
56
+ Requires-Dist: semgrep>=1.50.0; extra == "dev"
57
+ Provides-Extra: all
58
+ Requires-Dist: casbin>=1.0.0; extra == "all"
59
+ Requires-Dist: casbin-motor-adapter>=0.1.0; extra == "all"
60
+ Requires-Dist: oso-cloud>=0.1.0; extra == "all"
61
+ Dynamic: author
62
+ Dynamic: home-page
63
+ Dynamic: license-file
64
+ Dynamic: requires-python
65
+
66
+ # mdb-engine
67
+
68
+ **The MongoDB Engine for Python Apps** — Auto-sandboxing, index management, and auth in one package.
69
+
70
+ [![PyPI](https://img.shields.io/pypi/v/mdb-engine)](https://pypi.org/project/mdb-engine/)
71
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
72
+ [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](https://opensource.org/licenses/AGPL-3.0)
73
+
74
+ ---
75
+
76
+ ## Installation
77
+
78
+ ```bash
79
+ pip install mdb-engine
80
+ ```
81
+
82
+ ---
83
+
84
+ ## 30-Second Quick Start
85
+
86
+ ```python
87
+ from pathlib import Path
88
+ from mdb_engine import MongoDBEngine
89
+
90
+ # 1. Initialize the engine
91
+ engine = MongoDBEngine(
92
+ mongo_uri="mongodb://localhost:27017",
93
+ db_name="my_database"
94
+ )
95
+
96
+ # 2. Create a FastAPI app with automatic lifecycle management
97
+ app = engine.create_app(slug="my_app", manifest=Path("manifest.json"))
98
+
99
+ # 3. Use the scoped database - all queries automatically isolated
100
+ @app.post("/tasks")
101
+ async def create_task(task: dict):
102
+ db = engine.get_scoped_db("my_app")
103
+ result = await db.tasks.insert_one(task)
104
+ return {"id": str(result.inserted_id)}
105
+ ```
106
+
107
+ That's it. Your data is automatically sandboxed, indexes are created, and cleanup is handled.
108
+
109
+ ---
110
+
111
+ ## Basic Examples
112
+
113
+ ### 1. Index Management
114
+
115
+ Define indexes in your `manifest.json` — they're auto-created on startup:
116
+
117
+ ```json
118
+ {
119
+ "schema_version": "2.0",
120
+ "slug": "my_app",
121
+ "name": "My App",
122
+ "status": "active",
123
+ "managed_indexes": {
124
+ "tasks": [
125
+ {
126
+ "type": "regular",
127
+ "keys": {"status": 1, "created_at": -1},
128
+ "name": "status_sort"
129
+ },
130
+ {
131
+ "type": "regular",
132
+ "keys": {"priority": -1},
133
+ "name": "priority_idx"
134
+ }
135
+ ],
136
+ "users": [
137
+ {
138
+ "type": "regular",
139
+ "keys": {"email": 1},
140
+ "name": "email_unique",
141
+ "unique": true
142
+ }
143
+ ]
144
+ }
145
+ }
146
+ ```
147
+
148
+ Supported index types: `regular`, `text`, `vector`, `ttl`, `compound`.
149
+
150
+ ### 2. CRUD Operations (Auto-Scoped)
151
+
152
+ All database operations are automatically scoped to your app:
153
+
154
+ ```python
155
+ db = engine.get_scoped_db("my_app")
156
+
157
+ # Create
158
+ await db.tasks.insert_one({"title": "Build feature", "status": "pending"})
159
+
160
+ # Read
161
+ tasks = await db.tasks.find({"status": "pending"}).to_list(length=10)
162
+
163
+ # Update
164
+ await db.tasks.update_one({"_id": task_id}, {"$set": {"status": "done"}})
165
+
166
+ # Delete
167
+ await db.tasks.delete_one({"_id": task_id})
168
+ ```
169
+
170
+ **What happens under the hood:**
171
+ ```python
172
+ # You write:
173
+ await db.tasks.find({}).to_list(length=10)
174
+
175
+ # Engine executes:
176
+ # Collection: my_app_tasks
177
+ # Query: {"app_id": "my_app"}
178
+ ```
179
+
180
+ ### 3. Health Checks
181
+
182
+ Built-in observability:
183
+
184
+ ```python
185
+ @app.get("/health")
186
+ async def health():
187
+ status = await engine.get_health_status()
188
+ return {"status": status.get("status", "unknown")}
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Why mdb-engine?
194
+
195
+ - **Zero boilerplate** — No more connection setup, index creation scripts, or auth handlers
196
+ - **Data isolation** — Multi-tenant ready with automatic app sandboxing
197
+ - **Manifest-driven** — Define your app's "DNA" in JSON, not scattered code
198
+ - **No lock-in** — Standard Motor/PyMongo underneath; export anytime with `mongodump --query='{"app_id":"my_app"}'`
199
+
200
+ ---
201
+
202
+ ## Advanced Features
203
+
204
+ | Feature | Description | Learn More |
205
+ |---------|-------------|------------|
206
+ | **Authentication** | JWT + Casbin/OSO RBAC | [Auth Guide](https://github.com/ranfysvalle02/mdb-engine/blob/main/docs/AUTHZ.md) |
207
+ | **Vector Search** | Atlas Vector Search + embeddings | [RAG Example](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/basic/interactive_rag) |
208
+ | **Memory Service** | Persistent AI memory with Mem0 | [Chat Example](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/basic/chit_chat) |
209
+ | **WebSockets** | Real-time updates from manifest | [Docs](https://github.com/ranfysvalle02/mdb-engine/blob/main/docs/ARCHITECTURE.md) |
210
+ | **Multi-App** | Secure cross-app data access | [Multi-App Example](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/advanced/multi_app) |
211
+ | **SSO** | Shared auth across apps | [Shared Auth Example](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/advanced/multi_app_shared) |
212
+
213
+ ---
214
+
215
+ ## Full Examples
216
+
217
+ Clone and run:
218
+
219
+ ```bash
220
+ git clone https://github.com/ranfysvalle02/mdb-engine.git
221
+ cd mdb-engine/examples/basic/chit_chat
222
+ docker-compose up --build
223
+ ```
224
+
225
+ ### Basic Examples
226
+
227
+ | Example | Description |
228
+ |---------|-------------|
229
+ | [chit_chat](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/basic/chit_chat) | AI chat with persistent memory |
230
+ | [interactive_rag](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/basic/interactive_rag) | RAG with vector search |
231
+ | [oso_hello_world](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/basic/oso_hello_world) | OSO Cloud authorization |
232
+ | [parallax](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/basic/parallax) | Dynamic schema generation |
233
+ | [vector_hacking](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/basic/vector_hacking) | Vector embeddings & attacks |
234
+
235
+ ### Advanced Examples
236
+
237
+ | Example | Description |
238
+ |---------|-------------|
239
+ | [simple_app](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/advanced/simple_app) | Task management with `create_app()` pattern |
240
+ | [multi_app](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/advanced/multi_app) | Multi-tenant with cross-app access |
241
+ | [multi_app_shared](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples/advanced/multi_app_shared) | SSO with shared user pool |
242
+
243
+ ---
244
+
245
+ ## Manual Setup (Alternative)
246
+
247
+ If you need more control over the FastAPI lifecycle:
248
+
249
+ ```python
250
+ from pathlib import Path
251
+ from fastapi import FastAPI
252
+ from mdb_engine import MongoDBEngine
253
+
254
+ app = FastAPI()
255
+ engine = MongoDBEngine(mongo_uri="mongodb://localhost:27017", db_name="my_database")
256
+
257
+ @app.on_event("startup")
258
+ async def startup():
259
+ await engine.initialize()
260
+ manifest = await engine.load_manifest(Path("manifest.json"))
261
+ await engine.register_app(manifest, create_indexes=True)
262
+
263
+ @app.on_event("shutdown")
264
+ async def shutdown():
265
+ await engine.shutdown()
266
+
267
+ @app.get("/items")
268
+ async def get_items():
269
+ db = engine.get_scoped_db("my_app")
270
+ return await db.items.find({}).to_list(length=10)
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Links
276
+
277
+ - [GitHub Repository](https://github.com/ranfysvalle02/mdb-engine)
278
+ - [Documentation](https://github.com/ranfysvalle02/mdb-engine/tree/main/docs)
279
+ - [All Examples](https://github.com/ranfysvalle02/mdb-engine/tree/main/examples)
280
+ - [Quick Start Guide](https://github.com/ranfysvalle02/mdb-engine/blob/main/docs/QUICK_START.md)
281
+ - [Contributing](https://github.com/ranfysvalle02/mdb-engine/blob/main/CONTRIBUTING.md)
282
+
283
+ ---
284
+
285
+ **Stop building scaffolding. Start building features.**
@@ -0,0 +1,85 @@
1
+ mdb_engine/README.md,sha256=T3EFGcPopY9LslYW3lxgG3hohWkAOmBNbYG0FDMUJiY,3502
2
+ mdb_engine/__init__.py,sha256=d5UN7QnkySDKriO4epSGNS2bBbgl_Bw18qu6Sd4I7xs,1629
3
+ mdb_engine/config.py,sha256=EsB0PHrRCCt24db6Ly88s6PQ3sm1esSLMa2G4AHpt5k,7315
4
+ mdb_engine/constants.py,sha256=eaotvW57TVOg7rRbLziGrVNoP7adgw_G9iVByHezc_A,7837
5
+ mdb_engine/exceptions.py,sha256=N8WYOgh1fOH0yJeR9I3FTXqpACIL_EQX3zcfUgrFvPI,8521
6
+ mdb_engine/auth/README.md,sha256=pOobYo31ENhGA3d_nTUXVK795w2wvvQ_ub10x9wK1pU,33838
7
+ mdb_engine/auth/__init__.py,sha256=0Gc0uFDAcj_BMeACaD0oICAn8YwVcpTf20DJbTzDxr8,5656
8
+ mdb_engine/auth/audit.py,sha256=LtdG9GdwYTSMI30zMygB0K8w4l179GaGvkNbxWgoQ2I,17461
9
+ mdb_engine/auth/casbin_factory.py,sha256=CjGU7cj_I2OVjsendxpK1ungvHIMHzGJptMDw7LzEtE,5898
10
+ mdb_engine/auth/casbin_models.py,sha256=7XtFmRBhhjw1nKprnluvjyJoTj5fzdPeQwVvo6fI-r0,955
11
+ mdb_engine/auth/config_defaults.py,sha256=7JYX8CFI7OP7GHFIDHTf3Jns09LJcQ7f0_GL9yBnyuA,2018
12
+ mdb_engine/auth/config_helpers.py,sha256=DpQ8QZAO2FVVKFmhTJIa4FYPS8Iy8O7vcVh_tg0INLg,6309
13
+ mdb_engine/auth/cookie_utils.py,sha256=F88p6_aMG0aSmGXCn0KYjweSMPHqfce1lrKHU4P5yQk,4913
14
+ mdb_engine/auth/csrf.py,sha256=Rx9qYt8owSJJwwj7Z_w4nzkaLbaqWoVpNv13qnqosIA,12458
15
+ mdb_engine/auth/decorators.py,sha256=47uyOK_6WmK18J6ELRKwwgaIkcp6kHOILXuARj82Ijw,12288
16
+ mdb_engine/auth/dependencies.py,sha256=hAmFhtOFFJWRpCFQyPuALJWcgSMZn_Os16S7Q5N9waQ,27038
17
+ mdb_engine/auth/helpers.py,sha256=BCrid985cYh-3h5ZMUV9TES0q40uJXio4oYKQZta7KA,1970
18
+ mdb_engine/auth/integration.py,sha256=MHb4d8ar1eywXJlo4I1dlvUJ6SP7KO_ql3kbVTs8FAU,21756
19
+ mdb_engine/auth/jwt.py,sha256=aRXLfgFjsebIARmPqgfcA5zSgSN44HD7BgSyOEFaQCM,7244
20
+ mdb_engine/auth/middleware.py,sha256=uMx1dOO1NaR4K2nDet3k_ASR7rc7ZbKD0HlEkVYGJvU,10869
21
+ mdb_engine/auth/oso_factory.py,sha256=sJfW9TlrKp6QF_f5kq84axWQJyPsNelDDKuYLmVsduU,11257
22
+ mdb_engine/auth/provider.py,sha256=SNpkws-QO56hOo8CZ6LMenLjLQYO0NK_31zMhYekXx0,21926
23
+ mdb_engine/auth/rate_limiter.py,sha256=kYuYIDlgkmYB2jx_UUmM9VrndUq2iTkdP7DZV-Jfu8o,15825
24
+ mdb_engine/auth/restrictions.py,sha256=TXa2lO3lZQeMtokhyVLP19-XbWwq2R8JMTw2KfaiDMg,8852
25
+ mdb_engine/auth/session_manager.py,sha256=XjYeE4i1998tBIefhp8VH3Oe7reyA_CC_qjw6zZ5EVY,15459
26
+ mdb_engine/auth/shared_middleware.py,sha256=nrW-JN3P6SQ-WjJcXU9scX8auuS3-LdKEQX9Iy-IjJw,22343
27
+ mdb_engine/auth/shared_users.py,sha256=7f1Wl0u-egcnaMPj1a2XzclMnulrYXpzOcFQM6Mvvus,26828
28
+ mdb_engine/auth/token_lifecycle.py,sha256=NiYDEUyooZRNAaT79yPHAyAfTK3MGOu8eNJtClR-PL0,6753
29
+ mdb_engine/auth/token_store.py,sha256=Mpvln3sPEE0l5zQmFtWxpVUKYjelWv8FJTLhOOn55MY,9161
30
+ mdb_engine/auth/users.py,sha256=gMEHC936aTkjtnGN5E3YzA1k5IThDcLFhzs0-02ujxI,50037
31
+ mdb_engine/auth/utils.py,sha256=g5ILBsrSxvBbhHKsJc9oVjlnmodrM3QJjQQKbnEy4Mk,26126
32
+ mdb_engine/cli/__init__.py,sha256=PANRi4THmL34d1mawlqxIrnuItXMdqoMTq5Z1zHd7rM,301
33
+ mdb_engine/cli/main.py,sha256=Y5ELFhvsr8zxFWv4WScOGNHiLUTdSXAJeUFLpRXCelg,811
34
+ mdb_engine/cli/utils.py,sha256=0bpxHB5PmHapnCRjlN4T2YRp5kzJsp87Uh_65MsCFJY,2766
35
+ mdb_engine/cli/commands/__init__.py,sha256=ZSzMhKdV9ILD5EbOSxDV9nURHo1e4bQ0c8AWpqsTEqM,115
36
+ mdb_engine/cli/commands/generate.py,sha256=2XDnyROYm5OOcEFczGeS6P0AtFgM74XigQbxbMTPvU4,17329
37
+ mdb_engine/cli/commands/migrate.py,sha256=VqNiobSq-ykUhv7NyHJZ-wZ60a8X0B6OqXz8OACsCr0,2077
38
+ mdb_engine/cli/commands/show.py,sha256=-PmyMfzzG1HP-PsD9n8LECyxwvlXypNS3g_VDwFg4oY,1914
39
+ mdb_engine/cli/commands/validate.py,sha256=tD8GkhuW8LKsRMUXvBs-wvVWQunw1XFlLvbpE_SQ9Zg,1688
40
+ mdb_engine/core/README.md,sha256=cl19Sw4Hj-BPBsh_FIhPpop_6S88V-KaHC6rnUCx8xw,17039
41
+ mdb_engine/core/__init__.py,sha256=xhnXyXWZ0a2Qr49QrYvLE5QuqSalcpo05hHHRVtDz_M,1952
42
+ mdb_engine/core/app_registration.py,sha256=zRK2JTeT0rDW4XdOgFAV-j9Og7xijXdov4u1VVp7p1Y,13386
43
+ mdb_engine/core/app_secrets.py,sha256=ipLsC_QdnIFhrCLNQ3nXvBAfndSor4WNRJyqPc0-J8Q,10555
44
+ mdb_engine/core/connection.py,sha256=9WRccQ2Zz8K6PS6yC2XXxhZkppALvAWZJhfLmsJBnbI,8383
45
+ mdb_engine/core/encryption.py,sha256=jblhUuu_L_lht0qlbn5vqDsdj9rN80uL9DCFDCD-zxw,7540
46
+ mdb_engine/core/engine.py,sha256=hW86qxrHvaQdCJgyI93W0GVVxVB7ZUuY66QAiWaGXRA,55486
47
+ mdb_engine/core/index_management.py,sha256=9-r7MIy3JnjQ35sGqsbj8K_I07vAUWtAVgSWC99lJcE,5555
48
+ mdb_engine/core/manifest.py,sha256=K95aiGvZ2YQ3pUIGJyMeJTvveg9HgGdJUpd6fO7AxmI,132305
49
+ mdb_engine/core/ray_integration.py,sha256=Qe3jAYQhOKeBBlWFAcqzciDWN2zctJh_6uMTIai1tS0,13617
50
+ mdb_engine/core/seeding.py,sha256=I5g43xdoEdC4rNwc_Ih0L6QOZguPcpAWrS6HvJ2a3fE,6433
51
+ mdb_engine/core/service_initialization.py,sha256=gJNIB0As4vg6UXRgt1EDo5p3zzlHfF8NZqjCAlB75mA,12997
52
+ mdb_engine/core/types.py,sha256=v_lSnBTyl2JHX39cPvPsnOxXhu8xaGC92UektvYPOvg,11239
53
+ mdb_engine/database/README.md,sha256=cWPUce2PmrnIu4JQPF_RzsQ0Ju4pHIjhNhiFT0OdPKs,18481
54
+ mdb_engine/database/__init__.py,sha256=rrc3eZFli3K2zrvVdDbMBi8YkmoHYzP6JNT0AUBE5VU,981
55
+ mdb_engine/database/abstraction.py,sha256=FLVhFuS4OTZIRQyDkUBZdIlhqRndqNA89EO0cJvNsN0,23462
56
+ mdb_engine/database/connection.py,sha256=PDmwkjb4wYhLTUjlcYHscorces69rIuSxt5wdYixGQw,13777
57
+ mdb_engine/database/query_validator.py,sha256=AIWkQ-c6HAqJ-ixn-hq_0yfC2vdf1-jbEpzYZNmfEqs,13275
58
+ mdb_engine/database/resource_limiter.py,sha256=n54-I6bjEk5jxNGMXyb6_fArDCiyJ69_h9goFW5GzUs,6936
59
+ mdb_engine/database/scoped_wrapper.py,sha256=S_QIqGVyCteKAYlSUHNIqqc0S80jWhzHV-Lfa-ezNG4,94794
60
+ mdb_engine/embeddings/README.md,sha256=lehHJm7gADRze1Em59Da7DWFuVqDhMKmLz8UaTF12Rc,4997
61
+ mdb_engine/embeddings/__init__.py,sha256=UReBuU_0IOFg2kCpMjmZFV9b88PepL6oNok9Osd8t-4,2024
62
+ mdb_engine/embeddings/dependencies.py,sha256=aQXZnIVLxWU1qnKh-fih0iCcdX3cPd0AdsNEajBLp4w,5915
63
+ mdb_engine/embeddings/service.py,sha256=v5Ch4VMADDUw-tqNs8XbaG9JJktvO7cqniNJ8Mes56k,25991
64
+ mdb_engine/indexes/README.md,sha256=r7duq-1vtqHhBk1cwoBMYYh_dfTzxiaQaPE3mLB_3JQ,15341
65
+ mdb_engine/indexes/__init__.py,sha256=9QFJ6qo_yD26dZcKyKjj-hhesFpaomBt-mWTtYTQvqc,613
66
+ mdb_engine/indexes/helpers.py,sha256=v5iYqS3yOekqwxdbgnI1ifYH4oESatgXYJiJO1GvhSU,4259
67
+ mdb_engine/indexes/manager.py,sha256=CkA62LofmRLtfcm1cyzyx89p6Nge8yb3MIshmWAWPC8,32472
68
+ mdb_engine/memory/README.md,sha256=vy2FSXADcqG18YrFBfrMph9a1vYKuLijhs8ziNFdvRk,10631
69
+ mdb_engine/memory/__init__.py,sha256=e4kAYgxd_-WAH8GovTwjEBO9hvASu_kXEupMgksAL-U,1008
70
+ mdb_engine/memory/service.py,sha256=evoQhnslLVc3fEUhikdby_mt5iz9_T2LPeCEQX4Psd0,47553
71
+ mdb_engine/observability/README.md,sha256=CMgQaC1H8ESmCitfbhJifz6-XoXH_FPNE4MvuZ-oFas,13085
72
+ mdb_engine/observability/__init__.py,sha256=jjLsrW6Gy2ayrbfLrgHsDB61NxWWkYLHwv0q-N3fxjA,1213
73
+ mdb_engine/observability/health.py,sha256=kZ9LXcJ3_8tKXRWXNNCz3qsj0PkZ0BSTdzisc8ds2vw,9197
74
+ mdb_engine/observability/logging.py,sha256=yo_KnUtqjPx_KvqNrAxW8ud6HQjI7Lk6T7Lj7IMW1uY,4073
75
+ mdb_engine/observability/metrics.py,sha256=EL9-ZFOaxxIdU8PWIqPRyPZHhP3fc4VyUawRSS2GIY4,10726
76
+ mdb_engine/routing/README.md,sha256=WVvTQXDq0amryrjkCu0wP_piOEwFjLukjmPz2mroWHY,13658
77
+ mdb_engine/routing/__init__.py,sha256=reupjHi_RTc2ZBA4AH5XzobAmqy4EQIsfSUcTkFknUM,2438
78
+ mdb_engine/routing/websockets.py,sha256=X6-MG0mAN8ZEgdmZD8edaiDx8DqMCN-hV3coIOdgZNc,29346
79
+ mdb_engine/utils/__init__.py,sha256=_xjHB5p6WLWBql1DyDqf5zdjj2xpfMlK25Y6BH9-oFk,145
80
+ mdb_engine-0.1.7.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
81
+ mdb_engine-0.1.7.dist-info/METADATA,sha256=xhr0VvNWMKVjLgu-fkRbXzFWLf7nb8B5u_4J1LXkXfE,9305
82
+ mdb_engine-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
83
+ mdb_engine-0.1.7.dist-info/entry_points.txt,sha256=INCbYdFbBzJalwPwxliEzLmPfR57IvQ7RAXG_pn8cL8,48
84
+ mdb_engine-0.1.7.dist-info/top_level.txt,sha256=PH0UEBwTtgkm2vWvC9He_EOMn7hVn_Wg_Jyc0SmeO8k,11
85
+ mdb_engine-0.1.7.dist-info/RECORD,,