createsonline 0.1.26__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 (152) hide show
  1. createsonline/__init__.py +46 -0
  2. createsonline/admin/__init__.py +7 -0
  3. createsonline/admin/content.py +526 -0
  4. createsonline/admin/crud.py +805 -0
  5. createsonline/admin/field_builder.py +559 -0
  6. createsonline/admin/integration.py +482 -0
  7. createsonline/admin/interface.py +2562 -0
  8. createsonline/admin/model_creator.py +513 -0
  9. createsonline/admin/model_manager.py +388 -0
  10. createsonline/admin/modern_dashboard.py +498 -0
  11. createsonline/admin/permissions.py +264 -0
  12. createsonline/admin/user_forms.py +594 -0
  13. createsonline/ai/__init__.py +202 -0
  14. createsonline/ai/fields.py +1226 -0
  15. createsonline/ai/orm.py +325 -0
  16. createsonline/ai/services.py +1244 -0
  17. createsonline/app.py +506 -0
  18. createsonline/auth/__init__.py +8 -0
  19. createsonline/auth/management.py +228 -0
  20. createsonline/auth/models.py +552 -0
  21. createsonline/cli/__init__.py +5 -0
  22. createsonline/cli/commands/__init__.py +122 -0
  23. createsonline/cli/commands/database.py +416 -0
  24. createsonline/cli/commands/info.py +173 -0
  25. createsonline/cli/commands/initdb.py +218 -0
  26. createsonline/cli/commands/project.py +545 -0
  27. createsonline/cli/commands/serve.py +173 -0
  28. createsonline/cli/commands/shell.py +93 -0
  29. createsonline/cli/commands/users.py +148 -0
  30. createsonline/cli/main.py +2041 -0
  31. createsonline/cli/manage.py +274 -0
  32. createsonline/config/__init__.py +9 -0
  33. createsonline/config/app.py +2577 -0
  34. createsonline/config/database.py +179 -0
  35. createsonline/config/docs.py +384 -0
  36. createsonline/config/errors.py +160 -0
  37. createsonline/config/orm.py +43 -0
  38. createsonline/config/request.py +93 -0
  39. createsonline/config/settings.py +176 -0
  40. createsonline/data/__init__.py +23 -0
  41. createsonline/data/dataframe.py +925 -0
  42. createsonline/data/io.py +453 -0
  43. createsonline/data/series.py +557 -0
  44. createsonline/database/__init__.py +60 -0
  45. createsonline/database/abstraction.py +440 -0
  46. createsonline/database/assistant.py +585 -0
  47. createsonline/database/fields.py +442 -0
  48. createsonline/database/migrations.py +132 -0
  49. createsonline/database/models.py +604 -0
  50. createsonline/database.py +438 -0
  51. createsonline/http/__init__.py +28 -0
  52. createsonline/http/client.py +535 -0
  53. createsonline/ml/__init__.py +55 -0
  54. createsonline/ml/classification.py +552 -0
  55. createsonline/ml/clustering.py +680 -0
  56. createsonline/ml/metrics.py +542 -0
  57. createsonline/ml/neural.py +560 -0
  58. createsonline/ml/preprocessing.py +784 -0
  59. createsonline/ml/regression.py +501 -0
  60. createsonline/performance/__init__.py +19 -0
  61. createsonline/performance/cache.py +444 -0
  62. createsonline/performance/compression.py +335 -0
  63. createsonline/performance/core.py +419 -0
  64. createsonline/project_init.py +789 -0
  65. createsonline/routing.py +528 -0
  66. createsonline/security/__init__.py +34 -0
  67. createsonline/security/core.py +811 -0
  68. createsonline/security/encryption.py +349 -0
  69. createsonline/server.py +295 -0
  70. createsonline/static/css/admin.css +263 -0
  71. createsonline/static/css/common.css +358 -0
  72. createsonline/static/css/dashboard.css +89 -0
  73. createsonline/static/favicon.ico +0 -0
  74. createsonline/static/icons/icon-128x128.png +0 -0
  75. createsonline/static/icons/icon-128x128.webp +0 -0
  76. createsonline/static/icons/icon-16x16.png +0 -0
  77. createsonline/static/icons/icon-16x16.webp +0 -0
  78. createsonline/static/icons/icon-180x180.png +0 -0
  79. createsonline/static/icons/icon-180x180.webp +0 -0
  80. createsonline/static/icons/icon-192x192.png +0 -0
  81. createsonline/static/icons/icon-192x192.webp +0 -0
  82. createsonline/static/icons/icon-256x256.png +0 -0
  83. createsonline/static/icons/icon-256x256.webp +0 -0
  84. createsonline/static/icons/icon-32x32.png +0 -0
  85. createsonline/static/icons/icon-32x32.webp +0 -0
  86. createsonline/static/icons/icon-384x384.png +0 -0
  87. createsonline/static/icons/icon-384x384.webp +0 -0
  88. createsonline/static/icons/icon-48x48.png +0 -0
  89. createsonline/static/icons/icon-48x48.webp +0 -0
  90. createsonline/static/icons/icon-512x512.png +0 -0
  91. createsonline/static/icons/icon-512x512.webp +0 -0
  92. createsonline/static/icons/icon-64x64.png +0 -0
  93. createsonline/static/icons/icon-64x64.webp +0 -0
  94. createsonline/static/image/android-chrome-192x192.png +0 -0
  95. createsonline/static/image/android-chrome-512x512.png +0 -0
  96. createsonline/static/image/apple-touch-icon.png +0 -0
  97. createsonline/static/image/favicon-16x16.png +0 -0
  98. createsonline/static/image/favicon-32x32.png +0 -0
  99. createsonline/static/image/favicon.ico +0 -0
  100. createsonline/static/image/favicon.svg +17 -0
  101. createsonline/static/image/icon-128x128.png +0 -0
  102. createsonline/static/image/icon-128x128.webp +0 -0
  103. createsonline/static/image/icon-16x16.png +0 -0
  104. createsonline/static/image/icon-16x16.webp +0 -0
  105. createsonline/static/image/icon-180x180.png +0 -0
  106. createsonline/static/image/icon-180x180.webp +0 -0
  107. createsonline/static/image/icon-192x192.png +0 -0
  108. createsonline/static/image/icon-192x192.webp +0 -0
  109. createsonline/static/image/icon-256x256.png +0 -0
  110. createsonline/static/image/icon-256x256.webp +0 -0
  111. createsonline/static/image/icon-32x32.png +0 -0
  112. createsonline/static/image/icon-32x32.webp +0 -0
  113. createsonline/static/image/icon-384x384.png +0 -0
  114. createsonline/static/image/icon-384x384.webp +0 -0
  115. createsonline/static/image/icon-48x48.png +0 -0
  116. createsonline/static/image/icon-48x48.webp +0 -0
  117. createsonline/static/image/icon-512x512.png +0 -0
  118. createsonline/static/image/icon-512x512.webp +0 -0
  119. createsonline/static/image/icon-64x64.png +0 -0
  120. createsonline/static/image/icon-64x64.webp +0 -0
  121. createsonline/static/image/logo-header-h100.png +0 -0
  122. createsonline/static/image/logo-header-h100.webp +0 -0
  123. createsonline/static/image/logo-header-h200@2x.png +0 -0
  124. createsonline/static/image/logo-header-h200@2x.webp +0 -0
  125. createsonline/static/image/logo.png +0 -0
  126. createsonline/static/js/admin.js +274 -0
  127. createsonline/static/site.webmanifest +35 -0
  128. createsonline/static/templates/admin/base.html +87 -0
  129. createsonline/static/templates/admin/dashboard.html +217 -0
  130. createsonline/static/templates/admin/model_form.html +270 -0
  131. createsonline/static/templates/admin/model_list.html +202 -0
  132. createsonline/static/test_script.js +15 -0
  133. createsonline/static/test_styles.css +59 -0
  134. createsonline/static_files.py +365 -0
  135. createsonline/templates/404.html +100 -0
  136. createsonline/templates/admin_login.html +169 -0
  137. createsonline/templates/base.html +102 -0
  138. createsonline/templates/index.html +151 -0
  139. createsonline/templates.py +205 -0
  140. createsonline/testing.py +322 -0
  141. createsonline/utils.py +448 -0
  142. createsonline/validation/__init__.py +49 -0
  143. createsonline/validation/fields.py +598 -0
  144. createsonline/validation/models.py +504 -0
  145. createsonline/validation/validators.py +561 -0
  146. createsonline/views.py +184 -0
  147. createsonline-0.1.26.dist-info/METADATA +46 -0
  148. createsonline-0.1.26.dist-info/RECORD +152 -0
  149. createsonline-0.1.26.dist-info/WHEEL +5 -0
  150. createsonline-0.1.26.dist-info/entry_points.txt +2 -0
  151. createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
  152. createsonline-0.1.26.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2577 @@
1
+ # createsonline/config/app.py
2
+ """
3
+ CREATESONLINE Application Factory
4
+
5
+ The main application factory for the CREATESONLINE framework.
6
+ Built for AI-native web development.
7
+
8
+ Supports Python 3.9 through 3.13 with zero external dependencies.
9
+ """
10
+ from typing import Dict, Any, Optional, List, Callable
11
+ import sys
12
+ import json
13
+ from datetime import datetime
14
+ from urllib.parse import parse_qs
15
+
16
+ # Python version check (3.9-3.13 support)
17
+ if sys.version_info < (3, 9) or sys.version_info >= (3, 14):
18
+ raise RuntimeError(f"CREATESONLINE supports Python 3.9-3.13. Current: {sys.version}")
19
+
20
+ # Import from extracted modules
21
+ from .errors import HTTPException, ErrorPageGenerator
22
+ from .request import CreatesonlineInternalRequest
23
+ from .docs import APIDocumentationGenerator
24
+
25
+
26
+ class CreatesonlineApp:
27
+ """
28
+ CREATESONLINE Framework Application
29
+
30
+ The main application class for building AI-native web applications.
31
+ Pure internal implementation with zero external dependencies.
32
+
33
+ Features:
34
+ - Pure AI-native routing and middleware
35
+ - Built-in admin interface
36
+ - User management system
37
+ - Intelligent request/response handling
38
+ - Automatic API documentation
39
+ - Vector search capabilities
40
+ - LLM integration ready
41
+ - Complete internal implementation
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ title: str = "CREATESONLINE Application",
47
+ description: str = "Built with CREATESONLINE - The AI-Native Framework",
48
+ version: str = "1.0.0",
49
+ ai_config: Optional[Dict[str, Any]] = None,
50
+ debug: bool = False,
51
+ cors_origins: Optional[List[str]] = None,
52
+ **kwargs
53
+ ):
54
+ """
55
+ Initialize CREATESONLINE application
56
+
57
+ Args:
58
+ title: Application title
59
+ description: Application description
60
+ version: Application version
61
+ ai_config: AI configuration dictionary
62
+ debug: Enable debug mode
63
+ cors_origins: Allowed CORS origins
64
+ **kwargs: Additional configuration options
65
+ """
66
+ # Core application metadata
67
+ self.title = title
68
+ self.description = description
69
+ self.version = version
70
+ self.debug = debug
71
+ self.ai_config = ai_config or {}
72
+
73
+ # Internal application state
74
+ self._routes: List[Dict[str, Any]] = []
75
+ self._middleware: List[Dict[str, Any]] = []
76
+ self._startup_handlers: List[Callable] = []
77
+ self._shutdown_handlers: List[Callable] = []
78
+
79
+ # AI features registry
80
+ self._ai_features: List[str] = []
81
+
82
+ # Internal routing system
83
+ self._internal_routes = {}
84
+
85
+ # Initialize pure internal application
86
+ self._setup_internal_app(cors_origins)
87
+
88
+ # Setup framework routes (works with both implementations)
89
+ self._setup_framework_routes()
90
+ self._setup_error_handlers()
91
+
92
+ @property
93
+ def routes(self):
94
+ """Backward compatibility property for _internal_routes"""
95
+ return self._internal_routes
96
+
97
+ def _setup_internal_app(self, cors_origins: Optional[List[str]] = None):
98
+ """Setup internal ASGI application"""
99
+
100
+ # Store CORS configuration for internal implementation
101
+ self._cors_origins = cors_origins or (["*"] if self.debug else [])
102
+ self._enable_gzip = True
103
+
104
+ def _setup_framework_routes(self):
105
+ """Setup built-in CREATESONLINE routes"""
106
+
107
+ # Framework root endpoint
108
+ @self.get("/")
109
+ async def root_endpoint(request):
110
+ return await self._root_endpoint(request)
111
+
112
+ # Health check
113
+ @self.get("/health")
114
+ async def health_endpoint(request):
115
+ return await self._health_endpoint(request)
116
+
117
+ # Framework info
118
+ @self.get("/framework/info")
119
+ async def framework_info_endpoint(request):
120
+ return await self._framework_info_endpoint(request)
121
+
122
+ def _setup_error_handlers(self):
123
+ """Setup CREATESONLINE error handling - pure internal implementation"""
124
+ # Error handling is now done in the internal ASGI handler
125
+ pass
126
+
127
+ async def _root_endpoint(self, request) -> Dict[str, Any]:
128
+ """CREATESONLINE framework root endpoint"""
129
+ return {
130
+ "framework": "CREATESONLINE",
131
+ "application": self.title,
132
+ "version": self.version,
133
+ "tagline": "Build Intelligence Into Everything",
134
+ "status": "operational",
135
+ "mode": "internal",
136
+ "timestamp": datetime.utcnow().isoformat(),
137
+ "admin_interface": "/admin",
138
+ "api_documentation": "/docs",
139
+ "health_check": "/health",
140
+ "ai_enabled": len(self._ai_features) > 0,
141
+ "ai_features": self._ai_features,
142
+ "python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
143
+ "supported_python": "3.9-3.13"
144
+ }
145
+
146
+ async def _health_endpoint(self, request) -> Dict[str, Any]:
147
+ """CREATESONLINE health check endpoint"""
148
+ return {
149
+ "status": "healthy",
150
+ "framework": "CREATESONLINE",
151
+ "version": self.version,
152
+ "mode": "internal",
153
+ "timestamp": datetime.utcnow().isoformat(),
154
+ "ai_enabled": len(self._ai_features) > 0,
155
+ "python_version": f"{sys.version_info.major}.{sys.version_info.minor}",
156
+ "system_checks": {
157
+ "database": "ready",
158
+ "ai_services": "operational",
159
+ "memory": "optimal",
160
+ "internal_asgi": True
161
+ }
162
+ }
163
+
164
+ async def _framework_info_endpoint(self, request) -> Dict[str, Any]:
165
+ """CREATESONLINE framework information endpoint"""
166
+ return {
167
+ "framework": {
168
+ "name": "CREATESONLINE",
169
+ "version": self.version,
170
+ "description": self.description,
171
+ "tagline": "Build Intelligence Into Everything",
172
+ "architecture": "AI-Native",
173
+ "foundation": "Internal ASGI",
174
+ "python_support": "3.9-3.13"
175
+ },
176
+ "application": {
177
+ "title": self.title,
178
+ "version": self.version,
179
+ "debug": self.debug
180
+ },
181
+ "ai_configuration": self.ai_config,
182
+ "enabled_features": self._ai_features,
183
+ "dependencies": {
184
+ "pure_internal": True,
185
+ "external_ai": self._check_external_ai(),
186
+ "mode": "core"
187
+ },
188
+ "capabilities": [
189
+ "AI-Enhanced Fields",
190
+ "Built-in Admin Interface",
191
+ "User Management System",
192
+ "Natural Language Queries",
193
+ "Vector Similarity Search",
194
+ "LLM Integration",
195
+ "Smart Routing",
196
+ "Intelligent Middleware",
197
+ "Pure Python Core"
198
+ ],
199
+ "endpoints": {
200
+ "admin": "/admin",
201
+ "health": "/health",
202
+ "api_spec": "/docs"
203
+ }
204
+ }
205
+
206
+ def _generate_api_paths(self) -> Dict[str, Any]:
207
+ """Generate OpenAPI paths from routes"""
208
+ paths = {}
209
+ for route_key in self._internal_routes.keys():
210
+ method, path = route_key.split(':', 1)
211
+ if path not in paths:
212
+ paths[path] = {}
213
+ paths[path][method.lower()] = {
214
+ "summary": f"{method} {path}",
215
+ "responses": {
216
+ "200": {"description": "Success"}
217
+ }
218
+ }
219
+ return paths
220
+
221
+ def _check_external_ai(self) -> bool:
222
+ """Check if external AI services are available"""
223
+ try:
224
+ import openai
225
+ return True
226
+ except ImportError:
227
+ return False
228
+
229
+ # ========================================
230
+ # CREATESONLINE ROUTING API
231
+ # ========================================
232
+
233
+ def get(self, path: str, **kwargs) -> Callable:
234
+ """CREATESONLINE GET route decorator"""
235
+ return self._add_route("GET", path, **kwargs)
236
+
237
+ def post(self, path: str, **kwargs) -> Callable:
238
+ """CREATESONLINE POST route decorator"""
239
+ return self._add_route("POST", path, **kwargs)
240
+
241
+ def put(self, path: str, **kwargs) -> Callable:
242
+ """CREATESONLINE PUT route decorator"""
243
+ return self._add_route("PUT", path, **kwargs)
244
+
245
+ def delete(self, path: str, **kwargs) -> Callable:
246
+ """CREATESONLINE DELETE route decorator"""
247
+ return self._add_route("DELETE", path, **kwargs)
248
+
249
+ def route(
250
+ self,
251
+ path: str,
252
+ methods: Optional[List[str]] = None,
253
+ **kwargs
254
+ ) -> Callable:
255
+ """CREATESONLINE multi-method route decorator"""
256
+ if methods is None:
257
+ methods = ["GET"]
258
+
259
+ def decorator(func: Callable) -> Callable:
260
+ for method in methods:
261
+ self._add_route_internal(method.upper(), path, func, **kwargs)
262
+ return func
263
+ return decorator
264
+
265
+ def _add_route(self, method: str, path: str, **kwargs) -> Callable:
266
+ """Add route to router"""
267
+ def decorator(func: Callable) -> Callable:
268
+ self._add_route_internal(method, path, func, **kwargs)
269
+ return func
270
+ return decorator
271
+
272
+ def _add_route_internal(self, method: str, path: str, func: Callable, **kwargs):
273
+ """Internal route registration"""
274
+ route_key = f"{method}:{path}"
275
+
276
+ # Store in internal router only
277
+ self._internal_routes[route_key] = func
278
+
279
+
280
+ # ========================================
281
+ # CREATESONLINE MIDDLEWARE & EVENTS
282
+ # ========================================
283
+
284
+ def middleware(self, middleware_type: str = "http") -> Callable:
285
+ """Add custom middleware to CREATESONLINE application"""
286
+ def decorator(func: Callable) -> Callable:
287
+ self._middleware.append({
288
+ "type": middleware_type,
289
+ "func": func
290
+ })
291
+ return func
292
+ return decorator
293
+
294
+ def on_startup(self, func: Callable) -> Callable:
295
+ """Register CREATESONLINE startup event handler"""
296
+ self._startup_handlers.append(func)
297
+ return func
298
+
299
+ def on_shutdown(self, func: Callable) -> Callable:
300
+ """Register CREATESONLINE shutdown event handler"""
301
+ self._shutdown_handlers.append(func)
302
+ return func
303
+
304
+ def get_routes(self) -> List[str]:
305
+ """Get list of all registered routes"""
306
+ routes = set()
307
+ for route_key in self._internal_routes.keys():
308
+ # Extract path from "METHOD:path" format
309
+ if ':' in route_key:
310
+ path = route_key.split(':', 1)[1]
311
+ routes.add(path)
312
+ return sorted(list(routes))
313
+
314
+ # ========================================
315
+ # CREATESONLINE AI FEATURES
316
+ # ========================================
317
+
318
+ def enable_ai_features(self, features: List[str]) -> 'CreatesonlineApp':
319
+ """Enable AI features in CREATESONLINE application"""
320
+ for feature in features:
321
+ if feature not in self._ai_features:
322
+ self._ai_features.append(feature)
323
+
324
+ # Setup feature-specific routes
325
+ self._setup_ai_feature_routes(feature)
326
+
327
+ return self
328
+
329
+ def _setup_ai_feature_routes(self, feature: str):
330
+ """Setup AI feature-specific routes"""
331
+ if feature == "smart_query":
332
+ @self.get("/ai/query/{model:str}")
333
+ async def smart_query_endpoint(request):
334
+ return await self._smart_query_handler(request)
335
+
336
+ elif feature == "content_generation":
337
+ @self.post("/ai/generate")
338
+ async def content_generation_endpoint(request):
339
+ return await self._content_generation_handler(request)
340
+
341
+ elif feature == "vector_search":
342
+ @self.get("/ai/search")
343
+ async def vector_search_endpoint(request):
344
+ return await self._vector_search_handler(request)
345
+
346
+ elif feature == "model_serving":
347
+ @self.post("/ai/predict")
348
+ async def model_prediction_endpoint(request):
349
+ return await self._model_prediction_handler(request)
350
+
351
+ elif feature == "admin_ai":
352
+ @self.get("/admin/ai")
353
+ async def admin_ai_dashboard(request):
354
+ return await self._admin_ai_handler(request)
355
+
356
+ async def _smart_query_handler(self, request):
357
+ """Handle smart query requests"""
358
+ model = request.path_params.get('model', 'unknown')
359
+ return {
360
+ "framework": "CREATESONLINE",
361
+ "feature": "smart_query",
362
+ "mode": "internal",
363
+ "model": model,
364
+ "result": f"Smart query processed with CREATESONLINE AI using model: {model}"
365
+ }
366
+
367
+ async def _content_generation_handler(self, request):
368
+ """Handle content generation requests"""
369
+ return {
370
+ "framework": "CREATESONLINE",
371
+ "feature": "content_generation",
372
+ "mode": "internal",
373
+ "generated_content": "CREATESONLINE AI generated content"
374
+ }
375
+
376
+ async def _vector_search_handler(self, request):
377
+ """Handle vector search requests"""
378
+ return {
379
+ "framework": "CREATESONLINE",
380
+ "feature": "vector_search",
381
+ "mode": "internal",
382
+ "results": []
383
+ }
384
+
385
+ async def _model_prediction_handler(self, request):
386
+ """Handle model prediction requests"""
387
+ return {
388
+ "framework": "CREATESONLINE",
389
+ "feature": "model_serving",
390
+ "mode": "internal",
391
+ "prediction": 0.87
392
+ }
393
+
394
+ async def _admin_ai_handler(self, request):
395
+ """Handle admin AI dashboard requests"""
396
+ return {
397
+ "framework": "CREATESONLINE",
398
+ "feature": "admin_ai",
399
+ "mode": "internal",
400
+ "ai_dashboard": "AI-enhanced admin interface"
401
+ }
402
+
403
+ # ========================================
404
+ # ASGI INTERFACE
405
+ # ========================================
406
+
407
+ async def __call__(self, scope, receive, send):
408
+ """
409
+ CREATESONLINE ASGI callable interface
410
+
411
+ Pure internal ASGI implementation
412
+ """
413
+ # Execute startup handlers if this is the first request
414
+ if not getattr(self, '_startup_executed', False):
415
+ for handler in self._startup_handlers:
416
+ await handler()
417
+ self._startup_executed = True
418
+
419
+ # Use internal ASGI implementation
420
+ await self._internal_asgi_handler(scope, receive, send)
421
+
422
+ async def _internal_asgi_handler(self, scope, receive, send):
423
+ """Internal ASGI handler for zero-dependency mode"""
424
+
425
+ if scope['type'] == 'http':
426
+ await self._handle_internal_http(scope, receive, send)
427
+ elif scope['type'] == 'websocket':
428
+ await self._handle_internal_websocket(scope, receive, send)
429
+
430
+ async def _handle_internal_http(self, scope, receive, send):
431
+ """Handle HTTP requests with internal router"""
432
+
433
+ # On first request, discover routes from routes.py to override decorators
434
+ if getattr(self, '_needs_route_discovery', False):
435
+ try:
436
+ from createsonline.project_init import auto_discover_routes
437
+ auto_discover_routes(self)
438
+ self._needs_route_discovery = False
439
+ except Exception:
440
+ self._needs_route_discovery = False
441
+
442
+ path = scope['path']
443
+ method = scope['method']
444
+
445
+ # Serve static files first (favicon, logo, icons, CSS, JS, images)
446
+ if method == 'GET' and (
447
+ path.startswith('/icons/') or
448
+ path.startswith('/static/') or
449
+ path in ['/favicon.ico', '/site.webmanifest'] or
450
+ path.endswith(('.png', '.webp', '.jpg', '.jpeg', '.css', '.js', '.svg', '.ico'))
451
+ ):
452
+ await self._serve_static_file(path, scope, receive, send)
453
+ return
454
+
455
+ route_key = f"{method}:{path}"
456
+
457
+ # Create internal request object
458
+ request = CreatesonlineInternalRequest(scope, receive)
459
+
460
+ try:
461
+ # Find matching route - first try exact match
462
+ handler = None
463
+ path_params = {}
464
+
465
+ if route_key in self._internal_routes:
466
+ handler = self._internal_routes[route_key]
467
+ else:
468
+ # Try pattern matching for path parameters
469
+ handler, path_params = self._match_parametric_route(method, path)
470
+
471
+ if handler:
472
+ # Add path parameters to the request
473
+ request.path_params.update(path_params)
474
+ response_data = await handler(request)
475
+ else:
476
+ # 404 handler
477
+ accept_header = getattr(request, 'headers', {}).get('accept', '')
478
+ user_agent = getattr(request, 'headers', {}).get('user-agent', '')
479
+
480
+ # If browser request, return beautiful HTML error page
481
+ if ('text/html' in accept_header or 'Mozilla' in user_agent):
482
+ error_html = self._generate_error_page(
483
+ status_code=404,
484
+ error_message="The requested page could not be found.",
485
+ path=path,
486
+ method=method,
487
+ details="This endpoint is not available or may have been moved."
488
+ )
489
+ await send({
490
+ 'type': 'http.response.start',
491
+ 'status': 404,
492
+ 'headers': [
493
+ [b'content-type', b'text/html; charset=utf-8'],
494
+ [b'content-length', str(len(error_html.encode())).encode()],
495
+ ]
496
+ })
497
+ await send({
498
+ 'type': 'http.response.body',
499
+ 'body': error_html.encode()
500
+ })
501
+ return
502
+
503
+ # Otherwise return JSON error
504
+ response_data = {
505
+ "error": "Not Found",
506
+ "path": path,
507
+ "method": method,
508
+ "framework": "CREATESONLINE",
509
+ "mode": "internal",
510
+ "available_routes": list(self._internal_routes.keys())
511
+ }
512
+ status = 404
513
+
514
+ # Send response
515
+ await self._send_internal_response(send, response_data, status=locals().get('status', 200))
516
+
517
+ except Exception as e:
518
+ # Error handling
519
+ accept_header = getattr(request, 'headers', {}).get('accept', '')
520
+ user_agent = getattr(request, 'headers', {}).get('user-agent', '')
521
+
522
+ # If browser request, return beautiful HTML error page
523
+ if ('text/html' in accept_header or 'Mozilla' in user_agent):
524
+ error_html = self._generate_error_page(
525
+ status_code=500,
526
+ error_message="An internal server error occurred.",
527
+ path=getattr(request, 'path', ''),
528
+ method=getattr(request, 'method', 'GET'),
529
+ details=str(e) if self.debug else "Please try again later or contact support."
530
+ )
531
+ await send({
532
+ 'type': 'http.response.start',
533
+ 'status': 500,
534
+ 'headers': [
535
+ [b'content-type', b'text/html; charset=utf-8'],
536
+ [b'content-length', str(len(error_html.encode())).encode()],
537
+ ]
538
+ })
539
+ await send({
540
+ 'type': 'http.response.body',
541
+ 'body': error_html.encode()
542
+ })
543
+ return
544
+
545
+ # Otherwise return JSON error
546
+ error_data = {
547
+ "error": "Internal Server Error",
548
+ "message": str(e) if self.debug else "Something went wrong",
549
+ "framework": "CREATESONLINE",
550
+ "mode": "internal"
551
+ }
552
+ await self._send_internal_response(send, error_data, status=500)
553
+
554
+ async def _serve_static_file(self, path: str, scope, receive, send):
555
+ """Serve static files using Django-style STATICFILES_DIRS"""
556
+ from createsonline.static_files import static_handler
557
+
558
+ # Use the static handler which respects STATICFILES_DIRS
559
+ content, status, headers = static_handler.serve_file(path)
560
+
561
+ # Convert headers dict to ASGI format
562
+ asgi_headers = []
563
+ for key, value in headers.items():
564
+ asgi_headers.append([key.lower().encode(), str(value).encode()])
565
+
566
+ # Send response
567
+ await send({
568
+ 'type': 'http.response.start',
569
+ 'status': status,
570
+ 'headers': asgi_headers,
571
+ })
572
+ await send({
573
+ 'type': 'http.response.body',
574
+ 'body': content,
575
+ })
576
+
577
+ def _match_parametric_route(self, method: str, path: str):
578
+ """Match path against parametric routes and extract parameters"""
579
+ import re
580
+
581
+ for route_key, handler in self._internal_routes.items():
582
+ stored_method, route_pattern = route_key.split(':', 1)
583
+
584
+ if stored_method != method:
585
+ continue
586
+
587
+ # Check if this route has path parameters
588
+ if '{' not in route_pattern or '}' not in route_pattern:
589
+ continue
590
+
591
+ # Convert path pattern to regex
592
+ # Handle {param} and {param:path} patterns
593
+ regex_pattern = route_pattern
594
+ path_params = {}
595
+
596
+ # Find all parameter patterns
597
+ param_matches = re.findall(r'\{([^}]+)\}', route_pattern)
598
+
599
+ for param_match in param_matches:
600
+ if ':' in param_match:
601
+ # Handle {param_name:path} or {param_name:type} patterns
602
+ param_name, param_type = param_match.split(':', 1)
603
+ if param_type == 'path':
604
+ # Match any path including slashes
605
+ regex_pattern = regex_pattern.replace(f'{{{param_match}}}', f'(?P<{param_name}>.+)')
606
+ else:
607
+ # Match segments without slashes
608
+ regex_pattern = regex_pattern.replace(f'{{{param_match}}}', f'(?P<{param_name}>[^/]+)')
609
+ else:
610
+ # Handle simple {param} patterns - match segments without slashes
611
+ param_name = param_match
612
+ regex_pattern = regex_pattern.replace(f'{{{param_match}}}', f'(?P<{param_name}>[^/]+)')
613
+
614
+ # Try to match the path
615
+ match = re.match(f'^{regex_pattern}$', path)
616
+ if match:
617
+ path_params = match.groupdict()
618
+ return handler, path_params
619
+
620
+ return None, {}
621
+
622
+ async def _handle_internal_websocket(self, scope, receive, send):
623
+ """Handle WebSocket connections (internal implementation)"""
624
+ await send({'type': 'websocket.accept'})
625
+
626
+ while True:
627
+ message = await receive()
628
+ if message['type'] == 'websocket.disconnect':
629
+ break
630
+ elif message['type'] == 'websocket.receive':
631
+ await send({
632
+ 'type': 'websocket.send',
633
+ 'text': json.dumps({
634
+ "framework": "CREATESONLINE",
635
+ "mode": "internal",
636
+ "message": "WebSocket connected",
637
+ "received": message.get('text', '')
638
+ })
639
+ })
640
+
641
+ async def _send_internal_response(self, send, data, status=200):
642
+ """Send response using internal ASGI implementation"""
643
+
644
+ response_headers = {}
645
+
646
+ # Handle different response types
647
+ if hasattr(data, 'content') and hasattr(data, 'status_code'):
648
+ # Handle Response objects (like FileResponse, HTMLResponse, etc.)
649
+ content = data.content
650
+ status = getattr(data, 'status_code', status)
651
+ response_headers = getattr(data, 'headers', {})
652
+
653
+ if isinstance(content, bytes):
654
+ response_body = content
655
+ elif isinstance(content, str):
656
+ response_body = content.encode('utf-8')
657
+ elif isinstance(content, (dict, list)):
658
+ response_body = json.dumps(content, indent=2 if self.debug else None).encode('utf-8')
659
+ else:
660
+ response_body = str(content).encode('utf-8')
661
+ elif isinstance(data, dict) or isinstance(data, list):
662
+ # JSON response
663
+ response_body = json.dumps(data, indent=2 if self.debug else None).encode('utf-8')
664
+ elif isinstance(data, str):
665
+ # Text/HTML response
666
+ response_body = data.encode('utf-8')
667
+ else:
668
+ # Fallback
669
+ response_body = str(data).encode('utf-8')
670
+
671
+ # Build headers list
672
+ headers = [
673
+ [b'content-length', str(len(response_body)).encode()],
674
+ [b'x-framework', b'CREATESONLINE'],
675
+ [b'x-version', self.version.encode()],
676
+ [b'x-mode', b'internal'],
677
+ ]
678
+
679
+ # Add response-specific headers first (from Response object)
680
+ for key, value in response_headers.items():
681
+ if isinstance(key, str):
682
+ key = key.lower().encode()
683
+ if isinstance(value, str):
684
+ value = value.encode()
685
+ headers.append([key, value])
686
+
687
+ # Add default content-type if not set by Response object
688
+ content_type_set = any(header[0] == b'content-type' for header in headers)
689
+ if not content_type_set:
690
+ if isinstance(data, dict) or isinstance(data, list):
691
+ headers.append([b'content-type', b'application/json'])
692
+ elif isinstance(data, str) and data.strip().startswith('<'):
693
+ headers.append([b'content-type', b'text/html'])
694
+ else:
695
+ headers.append([b'content-type', b'text/plain'])
696
+
697
+ # Add CORS headers
698
+ if self._cors_origins and "*" in self._cors_origins:
699
+ headers.extend([
700
+ [b'access-control-allow-origin', b'*'],
701
+ [b'access-control-allow-methods', b'GET, POST, PUT, DELETE, OPTIONS'],
702
+ [b'access-control-allow-headers', b'*'],
703
+ ])
704
+
705
+ await send({
706
+ 'type': 'http.response.start',
707
+ 'status': status,
708
+ 'headers': headers,
709
+ })
710
+
711
+ await send({
712
+ 'type': 'http.response.body',
713
+ 'body': response_body,
714
+ })
715
+
716
+ # ========================================
717
+ # CREATESONLINE UTILITIES
718
+ # ========================================
719
+
720
+ def get_routes_info(self) -> List[Dict[str, Any]]:
721
+ """Get information about CREATESONLINE routes"""
722
+ routes_info = []
723
+ for route_key in self._internal_routes.keys():
724
+ method, path = route_key.split(':', 1)
725
+ routes_info.append({
726
+ "path": path,
727
+ "method": method,
728
+ "framework": "CREATESONLINE",
729
+ "mode": "internal"
730
+ })
731
+ return routes_info
732
+
733
+ def get_ai_config(self) -> Dict[str, Any]:
734
+ """Get current CREATESONLINE AI configuration"""
735
+ return {
736
+ "framework": "CREATESONLINE",
737
+ "mode": "internal",
738
+ "config": self.ai_config,
739
+ "enabled_features": self._ai_features,
740
+ "feature_count": len(self._ai_features),
741
+ "external_ai_available": self._check_external_ai()
742
+ }
743
+
744
+ def _generate_beautiful_api_docs(self):
745
+ """Generate beautiful HTML API documentation with dynamic backend data"""
746
+ import json
747
+ from datetime import datetime
748
+ import platform
749
+ import sys
750
+
751
+ # Get comprehensive API spec data with real backend info
752
+ spec = {
753
+ "openapi": "3.0.0",
754
+ "info": {
755
+ "title": self.title,
756
+ "description": self.description,
757
+ "version": self.version,
758
+ "x-framework": "CREATESONLINE",
759
+ "x-ai-enabled": len(self._ai_features) > 0,
760
+ "x-mode": "internal",
761
+ "x-timestamp": datetime.utcnow().isoformat(),
762
+ "x-python-version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
763
+ "x-platform": platform.system(),
764
+ "x-architecture": platform.machine()
765
+ },
766
+ "servers": [
767
+ {
768
+ "url": "/",
769
+ "description": "CREATESONLINE Development Server",
770
+ "variables": {
771
+ "protocol": {"default": "http", "enum": ["http", "https"]},
772
+ "host": {"default": "127.0.0.1:8000"}
773
+ }
774
+ }
775
+ ],
776
+ "paths": self._generate_enhanced_api_paths(),
777
+ "components": {
778
+ "schemas": self._generate_api_schemas(),
779
+ "securitySchemes": {
780
+ "ApiKeyAuth": {
781
+ "type": "apiKey",
782
+ "in": "header",
783
+ "name": "X-API-Key"
784
+ },
785
+ "BearerAuth": {
786
+ "type": "http",
787
+ "scheme": "bearer"
788
+ }
789
+ }
790
+ },
791
+ "x-system-info": {
792
+ "framework": "CREATESONLINE",
793
+ "mode": "AI-Native",
794
+ "features": self._ai_features,
795
+ "total_routes": len(self._internal_routes),
796
+ "ai_routes": len([r for r in self._internal_routes.keys() if 'ai' in r.lower()]),
797
+ "admin_routes": len([r for r in self._internal_routes.keys() if 'admin' in r.lower()]),
798
+ "startup_time": datetime.utcnow().isoformat(),
799
+ "health_status": "operational",
800
+ "debug_mode": self.debug
801
+ }
802
+ }
803
+
804
+ # Advanced HTML template with dynamic backend data
805
+ html_content = f"""
806
+ <!DOCTYPE html>
807
+ <html lang="en">
808
+ <head>
809
+ <meta charset="UTF-8">
810
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
811
+ <title>{self.title} - API Explorer</title>
812
+ <link rel="preconnect" href="https://fonts.googleapis.com">
813
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
814
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
815
+ <style>
816
+ * {{ margin: 0; padding: 0; box-sizing: border-box; }}
817
+
818
+ :root {{
819
+ /* CREATESONLINE Brand Colors */
820
+ --primary: #000000;
821
+ --secondary: #ffffff;
822
+ --accent: #6366f1;
823
+ --accent-hover: #4f46e5;
824
+
825
+ /* Gray Scale */
826
+ --gray-50: #fafafa;
827
+ --gray-100: #f5f5f5;
828
+ --gray-200: #e5e5e5;
829
+ --gray-300: #d4d4d4;
830
+ --gray-400: #a3a3a3;
831
+ --gray-500: #737373;
832
+ --gray-600: #525252;
833
+ --gray-700: #404040;
834
+ --gray-800: #262626;
835
+ --gray-900: #171717;
836
+
837
+ /* Status Colors */
838
+ --success: #10b981;
839
+ --success-bg: #ecfdf5;
840
+ --warning: #f59e0b;
841
+ --warning-bg: #fffbeb;
842
+ --error: #ef4444;
843
+ --error-bg: #fef2f2;
844
+ --info: #3b82f6;
845
+ --info-bg: #eff6ff;
846
+
847
+ /* Shadows */
848
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
849
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
850
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
851
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
852
+
853
+ /* Transitions */
854
+ --transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
855
+ --transition-slow: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
856
+ }}
857
+
858
+ html {{ scroll-behavior: smooth; }}
859
+
860
+ @keyframes rotate-pulse {{
861
+ 0% {{ transform: rotate(0deg) scale(1); }}
862
+ 25% {{ transform: rotate(10deg) scale(1.1); }}
863
+ 50% {{ transform: rotate(0deg) scale(1); }}
864
+ 75% {{ transform: rotate(-10deg) scale(1.1); }}
865
+ 100% {{ transform: rotate(0deg) scale(1); }}
866
+ }}
867
+
868
+ body {{
869
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
870
+ background: linear-gradient(135deg, #000000 0%, #ffffff 100%);
871
+ color: var(--gray-900);
872
+ line-height: 1.6;
873
+ min-height: 100vh;
874
+ }}
875
+
876
+ /* Header Section */
877
+ .header {{
878
+ background: linear-gradient(135deg, #000000 0%, #ffffff 100%);
879
+ color: var(--primary);
880
+ padding: 4rem 0 3rem;
881
+ position: relative;
882
+ overflow: hidden;
883
+ }}
884
+
885
+ .header::before {{
886
+ content: '';
887
+ position: absolute;
888
+ top: 0; left: 0; right: 0; bottom: 0;
889
+ background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="20" height="20" patternUnits="userSpaceOnUse"><path d="M 20 0 L 0 0 0 20" fill="none" stroke="rgba(255,255,255,0.05)" stroke-width="1"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
890
+ opacity: 0.7;
891
+ }}
892
+
893
+ .header-content {{
894
+ position: relative;
895
+ z-index: 2;
896
+ text-align: center;
897
+ }}
898
+
899
+ .header h1 {{
900
+ font-size: clamp(2.5rem, 5vw, 4rem);
901
+ font-weight: 900;
902
+ margin-bottom: 0.5rem;
903
+ background: linear-gradient(45deg, #ffffff, #f8fafc);
904
+ -webkit-background-clip: text;
905
+ -webkit-text-fill-color: transparent;
906
+ background-clip: text;
907
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
908
+ filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
909
+ }}
910
+
911
+ .header-description {{
912
+ font-size: 1.25rem;
913
+ color: #ffffff;
914
+ opacity: 0.95;
915
+ margin-bottom: 2rem;
916
+ max-width: 600px;
917
+ margin-left: auto;
918
+ margin-right: auto;
919
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
920
+ }}
921
+
922
+ .header-badges {{
923
+ display: flex;
924
+ justify-content: center;
925
+ gap: 1rem;
926
+ flex-wrap: wrap;
927
+ margin-bottom: 2rem;
928
+ }}
929
+
930
+ .badge {{
931
+ padding: 0.5rem 1rem;
932
+ border-radius: 50px;
933
+ font-size: 0.875rem;
934
+ font-weight: 600;
935
+ backdrop-filter: blur(10px);
936
+ border: 1px solid rgba(255, 255, 255, 0.2);
937
+ }}
938
+
939
+ .badge-version {{ background: rgba(16, 185, 129, 0.9); }}
940
+ .badge-ai {{ background: rgba(59, 130, 246, 0.9); }}
941
+ .badge-routes {{ background: rgba(168, 85, 247, 0.9); }}
942
+
943
+ /* Navigation Hover Effects */
944
+ .nav-link:hover {{
945
+ transform: translateY(-2px);
946
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3) !important;
947
+ background: rgba(255, 255, 255, 0.15) !important;
948
+ border-color: rgba(255, 255, 255, 0.4) !important;
949
+ }}
950
+
951
+ .nav-active:hover {{
952
+ transform: translateY(-2px);
953
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4) !important;
954
+ background: #f8fafc !important;
955
+ }}
956
+
957
+ .nav-link:active {{
958
+ transform: translateY(0px);
959
+ }}
960
+
961
+ .system-stats {{
962
+ display: grid;
963
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
964
+ gap: 1rem;
965
+ max-width: 800px;
966
+ margin: 0 auto;
967
+ }}
968
+
969
+ .stat-card {{
970
+ background: rgba(255, 255, 255, 0.1);
971
+ backdrop-filter: blur(10px);
972
+ border: 1px solid rgba(255, 255, 255, 0.2);
973
+ border-radius: 1rem;
974
+ padding: 1.5rem;
975
+ text-align: center;
976
+ }}
977
+
978
+ .stat-value {{
979
+ font-size: 2rem;
980
+ font-weight: 800;
981
+ color: #ffffff;
982
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
983
+ }}
984
+
985
+ .stat-label {{
986
+ font-size: 0.875rem;
987
+ color: #ffffff;
988
+ opacity: 0.9;
989
+ margin-top: 0.5rem;
990
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
991
+ }}
992
+
993
+ /* Main Content */
994
+ .container {{
995
+ max-width: 1400px;
996
+ margin: 0 auto;
997
+ padding: 0 2rem;
998
+ }}
999
+
1000
+ .api-layout {{
1001
+ display: grid;
1002
+ grid-template-columns: 350px 1fr;
1003
+ gap: 2rem;
1004
+ margin: 2rem 0;
1005
+ min-height: calc(100vh - 400px);
1006
+ }}
1007
+
1008
+ /* Sidebar */
1009
+ .sidebar {{
1010
+ background: var(--secondary);
1011
+ border-radius: 1rem;
1012
+ box-shadow: var(--shadow-lg);
1013
+ position: sticky;
1014
+ top: 2rem;
1015
+ height: fit-content;
1016
+ max-height: calc(100vh - 4rem);
1017
+ overflow: hidden;
1018
+ border: 1px solid var(--gray-200);
1019
+ }}
1020
+
1021
+ .sidebar-header {{
1022
+ background: linear-gradient(135deg, var(--primary), var(--gray-800));
1023
+ color: var(--secondary);
1024
+ padding: 1.5rem;
1025
+ font-weight: 700;
1026
+ font-size: 1.125rem;
1027
+ display: flex;
1028
+ align-items: center;
1029
+ gap: 0.75rem;
1030
+ }}
1031
+
1032
+ .sidebar-content {{
1033
+ max-height: calc(100vh - 8rem);
1034
+ overflow-y: auto;
1035
+ }}
1036
+
1037
+ .endpoint-filters {{
1038
+ padding: 1rem;
1039
+ border-bottom: 1px solid var(--gray-200);
1040
+ }}
1041
+
1042
+ .filter-tabs {{
1043
+ display: flex;
1044
+ gap: 0.5rem;
1045
+ flex-wrap: wrap;
1046
+ }}
1047
+
1048
+ .filter-tab {{
1049
+ padding: 0.5rem 1rem;
1050
+ border: none;
1051
+ background: var(--gray-100);
1052
+ color: var(--gray-600);
1053
+ border-radius: 0.5rem;
1054
+ cursor: pointer;
1055
+ font-size: 0.875rem;
1056
+ font-weight: 500;
1057
+ transition: var(--transition);
1058
+ }}
1059
+
1060
+ .filter-tab.active {{
1061
+ background: var(--primary);
1062
+ color: var(--secondary);
1063
+ }}
1064
+
1065
+ .endpoint-list {{
1066
+ list-style: none;
1067
+ padding: 0;
1068
+ }}
1069
+
1070
+ .endpoint-group {{
1071
+ border-bottom: 1px solid var(--gray-100);
1072
+ }}
1073
+
1074
+ .endpoint-group-title {{
1075
+ padding: 1rem;
1076
+ font-weight: 600;
1077
+ color: var(--gray-700);
1078
+ background: var(--gray-50);
1079
+ font-size: 0.875rem;
1080
+ text-transform: uppercase;
1081
+ letter-spacing: 0.05em;
1082
+ }}
1083
+
1084
+ .endpoint-item {{
1085
+ border-bottom: 1px solid var(--gray-100);
1086
+ cursor: pointer;
1087
+ transition: var(--transition);
1088
+ position: relative;
1089
+ }}
1090
+
1091
+ .endpoint-item:hover {{
1092
+ background: var(--gray-50);
1093
+ }}
1094
+
1095
+ .endpoint-item.active {{
1096
+ background: var(--primary);
1097
+ color: var(--secondary);
1098
+ }}
1099
+
1100
+ .endpoint-item.active::before {{
1101
+ content: '';
1102
+ position: absolute;
1103
+ left: 0;
1104
+ top: 0;
1105
+ bottom: 0;
1106
+ width: 4px;
1107
+ background: var(--accent);
1108
+ }}
1109
+
1110
+ .endpoint-link {{
1111
+ display: flex;
1112
+ align-items: center;
1113
+ padding: 1rem;
1114
+ text-decoration: none;
1115
+ color: inherit;
1116
+ gap: 1rem;
1117
+ }}
1118
+
1119
+ .method-badge {{
1120
+ display: inline-flex;
1121
+ align-items: center;
1122
+ justify-content: center;
1123
+ padding: 0.25rem 0.75rem;
1124
+ font-size: 0.75rem;
1125
+ font-weight: 700;
1126
+ font-family: 'JetBrains Mono', monospace;
1127
+ border-radius: 0.375rem;
1128
+ min-width: 70px;
1129
+ text-align: center;
1130
+ border: 2px solid;
1131
+ }}
1132
+
1133
+ .method-get {{ background: var(--success); color: white; border-color: var(--success); }}
1134
+ .method-post {{ background: var(--info); color: white; border-color: var(--info); }}
1135
+ .method-put {{ background: var(--warning); color: white; border-color: var(--warning); }}
1136
+ .method-delete {{ background: var(--error); color: white; border-color: var(--error); }}
1137
+ .method-patch {{ background: var(--accent); color: white; border-color: var(--accent); }}
1138
+
1139
+ .endpoint-path {{
1140
+ font-family: 'JetBrains Mono', monospace;
1141
+ flex: 1;
1142
+ overflow: hidden;
1143
+ text-overflow: ellipsis;
1144
+ white-space: nowrap;
1145
+ }}
1146
+
1147
+ /* Main Content Area */
1148
+ .main-content {{
1149
+ background: var(--secondary);
1150
+ border-radius: 1rem;
1151
+ box-shadow: var(--shadow-lg);
1152
+ overflow: hidden;
1153
+ border: 1px solid var(--gray-200);
1154
+ }}
1155
+
1156
+ .content-header {{
1157
+ background: linear-gradient(135deg, var(--gray-50), var(--gray-100));
1158
+ padding: 2rem;
1159
+ border-bottom: 1px solid var(--gray-200);
1160
+ }}
1161
+
1162
+ .endpoint-title {{
1163
+ font-size: 2.5rem;
1164
+ font-weight: 900;
1165
+ margin-bottom: 1rem;
1166
+ display: flex;
1167
+ align-items: center;
1168
+ gap: 1rem;
1169
+ flex-wrap: wrap;
1170
+ }}
1171
+
1172
+ .endpoint-description {{
1173
+ font-size: 1.125rem;
1174
+ color: var(--gray-600);
1175
+ margin-bottom: 1.5rem;
1176
+ padding: 1.5rem;
1177
+ background: var(--secondary);
1178
+ border-radius: 0.75rem;
1179
+ border-left: 4px solid var(--accent);
1180
+ box-shadow: var(--shadow-sm);
1181
+ }}
1182
+
1183
+ .endpoint-tags {{
1184
+ display: flex;
1185
+ gap: 0.5rem;
1186
+ flex-wrap: wrap;
1187
+ }}
1188
+
1189
+ .tag {{
1190
+ padding: 0.25rem 0.75rem;
1191
+ background: var(--accent);
1192
+ color: var(--secondary);
1193
+ border-radius: 0.375rem;
1194
+ font-size: 0.875rem;
1195
+ font-weight: 500;
1196
+ }}
1197
+
1198
+ .content-body {{
1199
+ padding: 2rem;
1200
+ }}
1201
+
1202
+ .section {{
1203
+ margin-bottom: 3rem;
1204
+ }}
1205
+
1206
+ .section-title {{
1207
+ font-size: 1.5rem;
1208
+ font-weight: 700;
1209
+ margin-bottom: 1rem;
1210
+ display: flex;
1211
+ align-items: center;
1212
+ gap: 0.5rem;
1213
+ padding-bottom: 0.5rem;
1214
+ border-bottom: 2px solid var(--gray-200);
1215
+ }}
1216
+
1217
+ /* Code Examples */
1218
+ .code-examples {{
1219
+ background: var(--gray-50);
1220
+ border-radius: 1rem;
1221
+ overflow: hidden;
1222
+ border: 1px solid var(--gray-200);
1223
+ }}
1224
+
1225
+ .code-tabs {{
1226
+ display: flex;
1227
+ background: var(--gray-100);
1228
+ border-bottom: 1px solid var(--gray-200);
1229
+ }}
1230
+
1231
+ .code-tab {{
1232
+ padding: 1rem 1.5rem;
1233
+ background: none;
1234
+ border: none;
1235
+ cursor: pointer;
1236
+ font-weight: 600;
1237
+ color: var(--gray-600);
1238
+ transition: var(--transition);
1239
+ border-bottom: 3px solid transparent;
1240
+ }}
1241
+
1242
+ .code-tab.active {{
1243
+ background: var(--secondary);
1244
+ color: var(--primary);
1245
+ border-bottom-color: var(--accent);
1246
+ }}
1247
+
1248
+ .code-content {{
1249
+ display: none;
1250
+ position: relative;
1251
+ }}
1252
+
1253
+ .code-content.active {{
1254
+ display: block;
1255
+ }}
1256
+
1257
+ .code-block {{
1258
+ background: var(--gray-900);
1259
+ color: var(--gray-100);
1260
+ padding: 2rem;
1261
+ font-family: 'JetBrains Mono', monospace;
1262
+ font-size: 0.875rem;
1263
+ line-height: 1.6;
1264
+ overflow-x: auto;
1265
+ position: relative;
1266
+ }}
1267
+
1268
+ .copy-btn {{
1269
+ position: absolute;
1270
+ top: 1rem;
1271
+ right: 1rem;
1272
+ background: var(--gray-700);
1273
+ color: var(--gray-100);
1274
+ border: none;
1275
+ padding: 0.5rem 1rem;
1276
+ border-radius: 0.375rem;
1277
+ cursor: pointer;
1278
+ font-size: 0.75rem;
1279
+ font-weight: 600;
1280
+ transition: var(--transition);
1281
+ }}
1282
+
1283
+ .copy-btn:hover {{
1284
+ background: var(--gray-600);
1285
+ }}
1286
+
1287
+ /* Try It Out Section */
1288
+ .try-it-section {{
1289
+ background: linear-gradient(135deg, var(--info-bg), var(--success-bg));
1290
+ border-radius: 1rem;
1291
+ padding: 2rem;
1292
+ border: 1px solid var(--info);
1293
+ margin: 2rem 0;
1294
+ }}
1295
+
1296
+ .try-it-header {{
1297
+ display: flex;
1298
+ align-items: center;
1299
+ justify-content: space-between;
1300
+ margin-bottom: 2rem;
1301
+ flex-wrap: wrap;
1302
+ gap: 1rem;
1303
+ }}
1304
+
1305
+ .try-it-title {{
1306
+ font-size: 1.5rem;
1307
+ font-weight: 700;
1308
+ color: var(--gray-900);
1309
+ display: flex;
1310
+ align-items: center;
1311
+ gap: 0.5rem;
1312
+ }}
1313
+
1314
+ .execute-btn {{
1315
+ background: linear-gradient(135deg, var(--accent), var(--accent-hover));
1316
+ color: var(--secondary);
1317
+ border: none;
1318
+ padding: 1rem 2rem;
1319
+ border-radius: 0.75rem;
1320
+ font-weight: 700;
1321
+ cursor: pointer;
1322
+ transition: var(--transition);
1323
+ font-family: inherit;
1324
+ font-size: 1rem;
1325
+ box-shadow: var(--shadow-md);
1326
+ }}
1327
+
1328
+ .execute-btn:hover {{
1329
+ transform: translateY(-2px);
1330
+ box-shadow: var(--shadow-lg);
1331
+ }}
1332
+
1333
+ .execute-btn:active {{
1334
+ transform: translateY(0);
1335
+ }}
1336
+
1337
+ .execute-btn.loading {{
1338
+ opacity: 0.7;
1339
+ pointer-events: none;
1340
+ }}
1341
+
1342
+ /* Response Section */
1343
+ .response-section {{
1344
+ margin-top: 2rem;
1345
+ border-radius: 1rem;
1346
+ overflow: hidden;
1347
+ border: 1px solid var(--gray-200);
1348
+ box-shadow: var(--shadow-md);
1349
+ }}
1350
+
1351
+ .response-header {{
1352
+ background: var(--gray-100);
1353
+ padding: 1rem 1.5rem;
1354
+ border-bottom: 1px solid var(--gray-200);
1355
+ display: flex;
1356
+ align-items: center;
1357
+ justify-content: space-between;
1358
+ }}
1359
+
1360
+ .status-indicator {{
1361
+ display: inline-flex;
1362
+ align-items: center;
1363
+ gap: 0.5rem;
1364
+ padding: 0.5rem 1rem;
1365
+ border-radius: 50px;
1366
+ font-weight: 600;
1367
+ font-size: 0.875rem;
1368
+ }}
1369
+
1370
+ .status-200 {{ background: var(--success-bg); color: var(--success); border: 1px solid var(--success); }}
1371
+ .status-400 {{ background: var(--error-bg); color: var(--error); border: 1px solid var(--error); }}
1372
+ .status-500 {{ background: var(--error-bg); color: var(--error); border: 1px solid var(--error); }}
1373
+
1374
+ .response-time {{
1375
+ font-family: 'JetBrains Mono', monospace;
1376
+ color: var(--gray-600);
1377
+ font-size: 0.875rem;
1378
+ }}
1379
+
1380
+ /* Welcome Message */
1381
+ .welcome-message {{
1382
+ text-align: center;
1383
+ padding: 4rem 2rem;
1384
+ color: var(--gray-600);
1385
+ }}
1386
+
1387
+ .welcome-message h2 {{
1388
+ font-size: 2.5rem;
1389
+ font-weight: 800;
1390
+ margin-bottom: 1rem;
1391
+ color: var(--gray-800);
1392
+ }}
1393
+
1394
+ .welcome-message p {{
1395
+ font-size: 1.125rem;
1396
+ margin-bottom: 2rem;
1397
+ max-width: 600px;
1398
+ margin-left: auto;
1399
+ margin-right: auto;
1400
+ }}
1401
+
1402
+ .quick-start {{
1403
+ background: var(--gray-50);
1404
+ border-radius: 1rem;
1405
+ padding: 2rem;
1406
+ margin-top: 2rem;
1407
+ border: 1px solid var(--gray-200);
1408
+ }}
1409
+
1410
+ .quick-start h3 {{
1411
+ font-size: 1.25rem;
1412
+ font-weight: 700;
1413
+ margin-bottom: 1rem;
1414
+ color: var(--gray-800);
1415
+ }}
1416
+
1417
+ /* Loading States */
1418
+ .loading-spinner {{
1419
+ display: inline-block;
1420
+ width: 20px;
1421
+ height: 20px;
1422
+ border: 3px solid rgba(255, 255, 255, 0.3);
1423
+ border-radius: 50%;
1424
+ border-top-color: var(--secondary);
1425
+ animation: spin 1s ease-in-out infinite;
1426
+ }}
1427
+
1428
+ @keyframes spin {{
1429
+ to {{ transform: rotate(360deg); }}
1430
+ }}
1431
+
1432
+ /* Responsive Design */
1433
+ @media (max-width: 1024px) {{
1434
+ .api-layout {{
1435
+ grid-template-columns: 1fr;
1436
+ gap: 1rem;
1437
+ }}
1438
+
1439
+ .sidebar {{
1440
+ position: static;
1441
+ max-height: none;
1442
+ }}
1443
+
1444
+ .header h1 {{
1445
+ font-size: 3rem;
1446
+ }}
1447
+
1448
+ .system-stats {{
1449
+ grid-template-columns: repeat(2, 1fr);
1450
+ }}
1451
+ }}
1452
+
1453
+ @media (max-width: 640px) {{
1454
+ .container {{
1455
+ padding: 0 1rem;
1456
+ }}
1457
+
1458
+ .header {{
1459
+ padding: 2rem 0;
1460
+ }}
1461
+
1462
+ .header h1 {{
1463
+ font-size: 2rem;
1464
+ }}
1465
+
1466
+ .header-badges {{
1467
+ flex-direction: column;
1468
+ align-items: center;
1469
+ }}
1470
+
1471
+ .system-stats {{
1472
+ grid-template-columns: 1fr;
1473
+ }}
1474
+
1475
+ .endpoint-title {{
1476
+ font-size: 1.75rem;
1477
+ flex-direction: column;
1478
+ align-items: flex-start;
1479
+ }}
1480
+
1481
+ .try-it-header {{
1482
+ flex-direction: column;
1483
+ align-items: stretch;
1484
+ }}
1485
+
1486
+ .execute-btn {{
1487
+ width: 100%;
1488
+ text-align: center;
1489
+ }}
1490
+ }}
1491
+ </style>
1492
+ </head>
1493
+ <body>
1494
+ <div class="header">
1495
+ <div class="header-nav" style="position: absolute; top: 1rem; right: 2rem; display: flex; gap: 1.5rem; z-index: 3;">
1496
+ <a href="/" class="nav-link" style="color: #ffffff; text-decoration: none; font-weight: 600; padding: 0.5rem 1rem; border-radius: 0.5rem; transition: all 0.3s ease; border: 2px solid rgba(255,255,255,0.2); backdrop-filter: blur(10px); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);">Home</a>
1497
+ <a href="/docs" class="nav-link nav-active" style="color: #000000; text-decoration: none; font-weight: 600; padding: 0.5rem 1rem; border-radius: 0.5rem; transition: all 0.3s ease; background: #ffffff; border: 2px solid #ffffff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);">API Docs</a>
1498
+ <a href="/admin" class="nav-link" style="color: #ffffff; text-decoration: none; font-weight: 600; padding: 0.5rem 1rem; border-radius: 0.5rem; transition: all 0.3s ease; border: 2px solid rgba(255,255,255,0.2); backdrop-filter: blur(10px); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);">Admin</a>
1499
+ <a href="/health" class="nav-link" style="color: #ffffff; text-decoration: none; font-weight: 600; padding: 0.5rem 1rem; border-radius: 0.5rem; transition: all 0.3s ease; border: 2px solid rgba(255,255,255,0.2); backdrop-filter: blur(10px); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);">Health</a>
1500
+ </div>
1501
+ <div class="container">
1502
+ <div class="header-content">
1503
+ <h1><img src="/static/image/favicon.ico" alt="CREATESONLINE" style="width: 48px; height: 48px; margin-right: 1rem; animation: rotate-pulse 3s ease-in-out infinite; vertical-align: middle;" />{self.title}</h1>
1504
+ <p class="header-description">{self.description}</p>
1505
+
1506
+ <div class="header-badges">
1507
+ <div class="badge badge-version">v{self.version}</div>
1508
+ <div class="badge badge-ai"><img src="/static/image/favicon.ico" alt="CREATESONLINE" style="width: 16px; height: 16px; margin-right: 0.5rem; vertical-align: middle;" />AI-Native</div>
1509
+ <div class="badge badge-routes">{spec['x-system-info']['total_routes']} Routes</div>
1510
+ </div>
1511
+
1512
+ <div class="system-stats">
1513
+ <div class="stat-card">
1514
+ <div class="stat-value">{spec['x-system-info']['total_routes']}</div>
1515
+ <div class="stat-label">Total Endpoints</div>
1516
+ </div>
1517
+ <div class="stat-card">
1518
+ <div class="stat-value">{spec['x-system-info']['ai_routes']}</div>
1519
+ <div class="stat-label">AI-Powered</div>
1520
+ </div>
1521
+ <div class="stat-card">
1522
+ <div class="stat-value">{len(spec['x-system-info']['features'])}</div>
1523
+ <div class="stat-label">AI Features</div>
1524
+ </div>
1525
+ <div class="stat-card">
1526
+ <div class="stat-value">{spec['info']['x-python-version']}</div>
1527
+ <div class="stat-label">Python Version</div>
1528
+ </div>
1529
+ </div>
1530
+ </div>
1531
+ </div>
1532
+ </div>
1533
+
1534
+ <div class="container">
1535
+ <div class="api-layout">
1536
+ <aside class="sidebar">
1537
+ <div class="sidebar-header">
1538
+ 📋 API Endpoints
1539
+ </div>
1540
+ <div class="sidebar-content">
1541
+ <div class="endpoint-filters">
1542
+ <div class="filter-tabs">
1543
+ <button class="filter-tab active" data-filter="all">All</button>
1544
+ <button class="filter-tab" data-filter="ai">AI</button>
1545
+ <button class="filter-tab" data-filter="admin">Admin</button>
1546
+ <button class="filter-tab" data-filter="system">System</button>
1547
+ </div>
1548
+ </div>
1549
+ <ul class="endpoint-list" id="endpointList">
1550
+ <!-- Dynamic endpoints will be loaded here -->
1551
+ </ul>
1552
+ </div>
1553
+ </aside>
1554
+
1555
+ <main class="main-content">
1556
+ <div id="endpointDetails">
1557
+ <div class="welcome-message">
1558
+ <h2>Welcome to {self.title} API</h2>
1559
+ <p>Explore our AI-native API with intelligent endpoints and real-time testing capabilities. Select an endpoint from the sidebar to get started.</p>
1560
+
1561
+ <div class="quick-start">
1562
+ <h3>🚀 Quick Start</h3>
1563
+ <div class="code-block">
1564
+ curl -X GET "{self._get_base_url()}/" \\
1565
+ -H "Accept: application/json" \\
1566
+ -H "User-Agent: MyApp/1.0"
1567
+ </div>
1568
+ </div>
1569
+ </div>
1570
+ </div>
1571
+ </main>
1572
+ </div>
1573
+ </div>
1574
+
1575
+ <script>
1576
+ // API Specification with all dynamic backend data
1577
+ const apiSpec = {json.dumps(spec, indent=2)};
1578
+
1579
+ class AdvancedAPIExplorer {{
1580
+ constructor() {{
1581
+ this.currentEndpoint = null;
1582
+ this.baseUrl = window.location.origin;
1583
+ this.currentFilter = 'all';
1584
+ this.currentCodeTab = 'curl';
1585
+ this.init();
1586
+ }}
1587
+
1588
+ init() {{
1589
+ this.renderEndpoints();
1590
+ this.setupEventListeners();
1591
+ this.setupFilters();
1592
+ this.displaySystemInfo();
1593
+ }}
1594
+
1595
+ setupEventListeners() {{
1596
+ // Filter tabs
1597
+ document.querySelectorAll('.filter-tab').forEach(tab => {{
1598
+ tab.addEventListener('click', (e) => {{
1599
+ this.setFilter(e.target.dataset.filter);
1600
+ }});
1601
+ }});
1602
+ }}
1603
+
1604
+ setupFilters() {{
1605
+ // Initialize filter functionality
1606
+ this.filterEndpoints(this.currentFilter);
1607
+ }}
1608
+
1609
+ setFilter(filter) {{
1610
+ this.currentFilter = filter;
1611
+
1612
+ // Update active tab
1613
+ document.querySelectorAll('.filter-tab').forEach(tab => {{
1614
+ tab.classList.remove('active');
1615
+ }});
1616
+ document.querySelector(`[data-filter="${{filter}}"]`).classList.add('active');
1617
+
1618
+ // Filter endpoints
1619
+ this.filterEndpoints(filter);
1620
+ }}
1621
+
1622
+ filterEndpoints(filter) {{
1623
+ const items = document.querySelectorAll('.endpoint-item');
1624
+ items.forEach(item => {{
1625
+ const tags = item.dataset.tags || '';
1626
+ const shouldShow = filter === 'all' ||
1627
+ tags.toLowerCase().includes(filter.toLowerCase());
1628
+ item.style.display = shouldShow ? 'block' : 'none';
1629
+ }});
1630
+ }}
1631
+
1632
+ displaySystemInfo() {{
1633
+ // console.log('🚀 CREATESONLINE API Explorer Loaded');
1634
+ // console.log('System Info:', apiSpec['x-system-info']);
1635
+ // console.log('Available Features:', apiSpec['x-system-info']['features']);
1636
+ }}
1637
+
1638
+ renderEndpoints() {{
1639
+ const endpointList = document.getElementById('endpointList');
1640
+ const paths = apiSpec.paths || {{}};
1641
+
1642
+ // Group endpoints by tags
1643
+ const groupedEndpoints = {{}};
1644
+
1645
+ Object.entries(paths).forEach(([path, methods]) => {{
1646
+ Object.entries(methods).forEach(([method, details]) => {{
1647
+ const tags = details.tags || ['API'];
1648
+ const primaryTag = tags[0];
1649
+
1650
+ if (!groupedEndpoints[primaryTag]) {{
1651
+ groupedEndpoints[primaryTag] = [];
1652
+ }}
1653
+
1654
+ groupedEndpoints[primaryTag].push({{
1655
+ path, method, details, tags: tags.join(' ')
1656
+ }});
1657
+ }});
1658
+ }});
1659
+
1660
+ // Render grouped endpoints
1661
+ Object.entries(groupedEndpoints).forEach(([group, endpoints]) => {{
1662
+ // Group header
1663
+ const groupDiv = document.createElement('div');
1664
+ groupDiv.className = 'endpoint-group';
1665
+
1666
+ const groupTitle = document.createElement('div');
1667
+ groupTitle.className = 'endpoint-group-title';
1668
+ groupTitle.textContent = group;
1669
+ groupDiv.appendChild(groupTitle);
1670
+
1671
+ // Group endpoints
1672
+ endpoints.forEach({{path, method, details, tags}}) => {{
1673
+ const li = document.createElement('li');
1674
+ li.className = 'endpoint-item';
1675
+ li.dataset.tags = tags;
1676
+ li.innerHTML = `
1677
+ <a href="#" class="endpoint-link" data-path="${{path}}" data-method="${{method}}">
1678
+ <span class="method-badge method-${{method}}">${{method.toUpperCase()}}</span>
1679
+ <span class="endpoint-path">${{path}}</span>
1680
+ </a>
1681
+ `;
1682
+
1683
+ li.addEventListener('click', (e) => {{
1684
+ e.preventDefault();
1685
+ this.showEndpointDetails(path, method, details);
1686
+ this.setActiveEndpoint(li);
1687
+ }});
1688
+
1689
+ groupDiv.appendChild(li);
1690
+ }});
1691
+
1692
+ endpointList.appendChild(groupDiv);
1693
+ }});
1694
+ }}
1695
+
1696
+ setActiveEndpoint(activeElement) {{
1697
+ document.querySelectorAll('.endpoint-item').forEach(item => {{
1698
+ item.classList.remove('active');
1699
+ }});
1700
+ activeElement.classList.add('active');
1701
+ }}
1702
+
1703
+ showEndpointDetails(path, method, details) {{
1704
+ this.currentEndpoint = {{ path, method, details }};
1705
+ const detailsContainer = document.getElementById('endpointDetails');
1706
+
1707
+ const codeSamples = details['x-code-samples'] || [];
1708
+ const parameters = details.parameters || [];
1709
+ const responses = details.responses || {{}};
1710
+
1711
+ detailsContainer.innerHTML = `
1712
+ <div class="content-header">
1713
+ <div class="endpoint-title">
1714
+ <span class="method-badge method-${{method}}">${{method.toUpperCase()}}</span>
1715
+ <span>${{path}}</span>
1716
+ </div>
1717
+
1718
+ <div class="endpoint-description">
1719
+ ${{details.description || details.summary || 'No description available'}}
1720
+ </div>
1721
+
1722
+ <div class="endpoint-tags">
1723
+ ${{(details.tags || []).map(tag => `<span class="tag">${{tag}}</span>`).join('')}}
1724
+ </div>
1725
+ </div>
1726
+
1727
+ <div class="content-body">
1728
+ ${{parameters.length > 0 ? `
1729
+ <div class="section">
1730
+ <h3 class="section-title">📝 Parameters</h3>
1731
+ <div class="parameters-grid">
1732
+ ${{parameters.map(param => `
1733
+ <div class="parameter-item">
1734
+ <div class="parameter-name">${{param.name}}</div>
1735
+ <div class="parameter-type">${{param.schema?.type || 'string'}}</div>
1736
+ <div class="parameter-description">${{param.description || 'No description'}}</div>
1737
+ <div class="parameter-required">${{param.required ? 'Required' : 'Optional'}}</div>
1738
+ </div>
1739
+ `).join('')}}
1740
+ </div>
1741
+ </div>
1742
+ ` : ''}}
1743
+
1744
+ <div class="section">
1745
+ <h3 class="section-title">💻 Code Examples</h3>
1746
+ <div class="code-examples">
1747
+ <div class="code-tabs">
1748
+ ${{codeSamples.map(sample => `
1749
+ <button class="code-tab ${{sample.lang === 'curl' ? 'active' : ''}}"
1750
+ data-lang="${{sample.lang}}">${{sample.lang.toUpperCase()}}</button>
1751
+ `).join('')}}
1752
+ </div>
1753
+ ${{codeSamples.map(sample => `
1754
+ <div class="code-content ${{sample.lang === 'curl' ? 'active' : ''}}"
1755
+ data-lang="${{sample.lang}}">
1756
+ <div class="code-block">
1757
+ <button class="copy-btn" onclick="this.copyCode(this)">📋 Copy</button>
1758
+ <pre>${{sample.source}}</pre>
1759
+ </div>
1760
+ </div>
1761
+ `).join('')}}
1762
+ </div>
1763
+ </div>
1764
+
1765
+ <div class="try-it-section">
1766
+ <div class="try-it-header">
1767
+ <h3 class="try-it-title">
1768
+ 🚀 Try It Out
1769
+ </h3>
1770
+ <button class="execute-btn" onclick="apiExplorer.executeRequest()">
1771
+ Execute Request
1772
+ </button>
1773
+ </div>
1774
+
1775
+ <div id="responseContainer" class="response-section" style="display: none;">
1776
+ <div class="response-header">
1777
+ <div id="responseStatus"></div>
1778
+ <div id="responseTime" class="response-time"></div>
1779
+ </div>
1780
+ <div id="responseContent"></div>
1781
+ </div>
1782
+ </div>
1783
+
1784
+ <div class="section">
1785
+ <h3 class="section-title">📊 Response Schema</h3>
1786
+ ${{this.renderResponseSchema(responses)}}
1787
+ </div>
1788
+ </div>
1789
+ `;
1790
+
1791
+ // Setup code tab switching
1792
+ this.setupCodeTabs();
1793
+ }}
1794
+
1795
+ setupCodeTabs() {{
1796
+ document.querySelectorAll('.code-tab').forEach(tab => {{
1797
+ tab.addEventListener('click', (e) => {{
1798
+ const lang = e.target.dataset.lang;
1799
+
1800
+ // Update active tab
1801
+ document.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));
1802
+ e.target.classList.add('active');
1803
+
1804
+ // Show corresponding content
1805
+ document.querySelectorAll('.code-content').forEach(content => {{
1806
+ content.classList.remove('active');
1807
+ }});
1808
+ document.querySelector(`[data-lang="${{lang}}"]`).classList.add('active');
1809
+ }});
1810
+ }});
1811
+ }}
1812
+
1813
+ copyCode(button) {{
1814
+ const code = button.nextElementSibling.textContent;
1815
+ navigator.clipboard.writeText(code).then(() => {{
1816
+ button.textContent = '✅ Copied!';
1817
+ setTimeout(() => {{
1818
+ button.textContent = '📋 Copy';
1819
+ }}, 2000);
1820
+ }});
1821
+ }}
1822
+
1823
+ renderResponseSchema(responses) {{
1824
+ let html = '';
1825
+ Object.entries(responses).forEach(([status, response]) => {{
1826
+ const statusClass = status.startsWith('2') ? 'status-200' :
1827
+ status.startsWith('4') ? 'status-400' : 'status-500';
1828
+ html += `
1829
+ <div style="margin-bottom: 1.5rem;">
1830
+ <div class="status-indicator ${{statusClass}}">
1831
+ <span>${{status}}</span>
1832
+ <span>${{response.description}}</span>
1833
+ </div>
1834
+ <div class="code-block" style="margin-top: 1rem;">
1835
+ <button class="copy-btn" onclick="apiExplorer.copyCode(this)">📋 Copy</button>
1836
+ <pre>${{JSON.stringify(response.content?.['application/json']?.example || {{}}, null, 2)}}</pre>
1837
+ </div>
1838
+ </div>
1839
+ `;
1840
+ }});
1841
+ return html || '<p>No response schema available</p>';
1842
+ }}
1843
+
1844
+ async executeRequest() {{
1845
+ if (!this.currentEndpoint) return;
1846
+
1847
+ const {{ path, method }} = this.currentEndpoint;
1848
+ const executeBtn = document.querySelector('.execute-btn');
1849
+ const responseContainer = document.getElementById('responseContainer');
1850
+ const responseStatus = document.getElementById('responseStatus');
1851
+ const responseTime = document.getElementById('responseTime');
1852
+ const responseContent = document.getElementById('responseContent');
1853
+
1854
+ // Show loading state
1855
+ executeBtn.classList.add('loading');
1856
+ executeBtn.innerHTML = '<span class="loading-spinner"></span> Executing...';
1857
+ responseContainer.style.display = 'block';
1858
+
1859
+ try {{
1860
+ const startTime = performance.now();
1861
+ const response = await fetch(path, {{
1862
+ method: method.toUpperCase(),
1863
+ headers: {{
1864
+ 'Accept': 'application/json',
1865
+ 'User-Agent': 'CREATESONLINE-API-Explorer/1.0'
1866
+ }}
1867
+ }});
1868
+ const endTime = performance.now();
1869
+ const responseTimeMs = Math.round(endTime - startTime);
1870
+
1871
+ let responseData;
1872
+ const contentType = response.headers.get('content-type') || '';
1873
+
1874
+ if (contentType.includes('application/json')) {{
1875
+ responseData = await response.json();
1876
+ }} else {{
1877
+ responseData = await response.text();
1878
+ }}
1879
+
1880
+ const statusClass = response.ok ? 'status-200' :
1881
+ response.status >= 400 && response.status < 500 ? 'status-400' : 'status-500';
1882
+
1883
+ responseStatus.innerHTML = `
1884
+ <div class="status-indicator ${{statusClass}}">
1885
+ <span>${{response.status}} ${{response.statusText}}</span>
1886
+ </div>
1887
+ `;
1888
+
1889
+ responseTime.textContent = `⏱️ ${{responseTimeMs}}ms`;
1890
+
1891
+ responseContent.innerHTML = `
1892
+ <div class="code-block">
1893
+ <button class="copy-btn" onclick="apiExplorer.copyCode(this)">📋 Copy</button>
1894
+ <pre>${{typeof responseData === 'object' ?
1895
+ JSON.stringify(responseData, null, 2) : responseData}}</pre>
1896
+ </div>
1897
+ `;
1898
+
1899
+ }} catch (error) {{
1900
+ responseStatus.innerHTML = `
1901
+ <div class="status-indicator status-400">
1902
+ <span>❌ Network Error</span>
1903
+ </div>
1904
+ `;
1905
+ responseTime.textContent = '';
1906
+ responseContent.innerHTML = `
1907
+ <div class="code-block">
1908
+ <pre>Error: ${{error.message}}</pre>
1909
+ </div>
1910
+ `;
1911
+ }} finally {{
1912
+ executeBtn.classList.remove('loading');
1913
+ executeBtn.textContent = 'Execute Request';
1914
+ }}
1915
+ }}
1916
+ }}
1917
+
1918
+ // Initialize the advanced API explorer
1919
+ const apiExplorer = new AdvancedAPIExplorer();
1920
+
1921
+ // Global functions for inline event handlers
1922
+ window.apiExplorer = apiExplorer;
1923
+ </script>
1924
+ </body>
1925
+ </html>
1926
+ """
1927
+
1928
+ # Use internal HTML response class
1929
+ class HTMLResponse:
1930
+ def __init__(self, content, status_code=200, headers=None):
1931
+ self.content = content
1932
+ self.status_code = status_code
1933
+ self.headers = headers or {'content-type': 'text/html'}
1934
+
1935
+ return HTMLResponse(html_content)
1936
+
1937
+ def _get_base_url(self):
1938
+ """Get base URL for API documentation"""
1939
+ return "http://127.0.0.1:8000" # Default for development
1940
+
1941
+ def _generate_enhanced_api_paths(self) -> dict:
1942
+ """Generate enhanced OpenAPI paths from routes with detailed info"""
1943
+ paths = {}
1944
+ for route_key in self._internal_routes.keys():
1945
+ method, path = route_key.split(':', 1)
1946
+ if path not in paths:
1947
+ paths[path] = {}
1948
+
1949
+ # Enhanced path information
1950
+ paths[path][method.lower()] = {
1951
+ "summary": f"{method.upper()} {path}",
1952
+ "description": self._get_route_description(path, method),
1953
+ "operationId": f"{method.lower()}_{path.replace('/', '_').replace('{', '').replace('}', '').strip('_')}",
1954
+ "tags": self._get_route_tags(path),
1955
+ "parameters": self._get_route_parameters(path),
1956
+ "responses": {
1957
+ "200": {
1958
+ "description": "Successful response",
1959
+ "content": {
1960
+ "application/json": {
1961
+ "schema": {"type": "object"},
1962
+ "example": self._get_example_response(path, method)
1963
+ }
1964
+ }
1965
+ },
1966
+ "400": {"description": "Bad request"},
1967
+ "404": {"description": "Not found"},
1968
+ "500": {"description": "Internal server error"}
1969
+ },
1970
+ "x-code-samples": [
1971
+ {
1972
+ "lang": "curl",
1973
+ "source": f"curl -X {method.upper()} '{self._get_base_url()}{path}' -H 'Accept: application/json'"
1974
+ },
1975
+ {
1976
+ "lang": "python",
1977
+ "source": f"import requests\nresponse = requests.{method.lower()}('{self._get_base_url()}{path}')\nprint(response.json())"
1978
+ },
1979
+ {
1980
+ "lang": "javascript",
1981
+ "source": f"fetch('{self._get_base_url()}{path}', {{\n method: '{method.upper()}',\n headers: {{\n 'Accept': 'application/json'\n }}\n}})\n.then(response => response.json())\n.then(data => console.log(data));"
1982
+ }
1983
+ ]
1984
+ }
1985
+ return paths
1986
+
1987
+ def _get_route_description(self, path: str, method: str) -> str:
1988
+ """Get description for a route based on its path"""
1989
+ descriptions = {
1990
+ "/": "Get framework information and status",
1991
+ "/health": "Health check endpoint with system metrics",
1992
+ "/examples": "Example endpoint showcasing framework capabilities",
1993
+ "/admin": "Admin interface for managing the application",
1994
+ "/api/status": "API status and operational information",
1995
+ "/docs": "Interactive API documentation and specification",
1996
+ "/docs": "Interactive API documentation",
1997
+ "/framework/info": "Detailed framework information and configuration"
1998
+ }
1999
+
2000
+ # Check for AI routes
2001
+ if '/ai/' in path:
2002
+ return "AI-powered endpoint with intelligent processing capabilities"
2003
+
2004
+ # Check for admin routes
2005
+ if '/admin/' in path:
2006
+ return "Administrative endpoint for system management"
2007
+
2008
+ return descriptions.get(path, f"API endpoint: {method.upper()} {path}")
2009
+
2010
+ def _get_route_tags(self, path: str) -> list:
2011
+ """Get tags for route categorization"""
2012
+ if path.startswith('/ai/'):
2013
+ return ["AI", "Machine Learning"]
2014
+ elif path.startswith('/admin/'):
2015
+ return ["Admin", "Management"]
2016
+ elif path in ['/health', '/api/status']:
2017
+ return ["System", "Health"]
2018
+ elif path in ['/', '/examples', '/framework/info']:
2019
+ return ["Framework", "Info"]
2020
+ else:
2021
+ return ["API"]
2022
+
2023
+ def _get_route_parameters(self, path: str) -> list:
2024
+ """Extract parameters from route path"""
2025
+ import re
2026
+ params = []
2027
+ param_matches = re.findall(r'\{([^}]+)\}', path)
2028
+
2029
+ for param in param_matches:
2030
+ param_info = {
2031
+ "name": param,
2032
+ "in": "path",
2033
+ "required": True,
2034
+ "schema": {"type": "string"},
2035
+ "description": f"Path parameter: {param}"
2036
+ }
2037
+
2038
+ # Type hints from parameter names
2039
+ if 'id' in param.lower():
2040
+ param_info["schema"] = {"type": "integer", "minimum": 1}
2041
+ param_info["description"] = f"Unique identifier for {param.replace('_id', '').replace('id', 'resource')}"
2042
+ elif 'model' in param.lower():
2043
+ param_info["schema"] = {"type": "string", "enum": ["gpt-3.5-turbo", "gpt-4", "claude-3"]}
2044
+ param_info["description"] = "AI model name"
2045
+
2046
+ params.append(param_info)
2047
+
2048
+ return params
2049
+
2050
+ def _get_example_response(self, path: str, method: str) -> dict:
2051
+ """Generate example responses based on route"""
2052
+ examples = {
2053
+ "/": {
2054
+ "framework": "CREATESONLINE",
2055
+ "version": self.version,
2056
+ "status": "operational",
2057
+ "ai_enabled": len(self._ai_features) > 0,
2058
+ "features": self._ai_features[:3] if self._ai_features else []
2059
+ },
2060
+ "/health": {
2061
+ "status": "healthy",
2062
+ "timestamp": "2024-01-15T10:30:00Z",
2063
+ "uptime": 86400,
2064
+ "system": {"memory": "45%", "cpu": "12%", "disk": "67%"}
2065
+ },
2066
+ "/examples": {
2067
+ "message": "CREATESONLINE Example Response",
2068
+ "capabilities": ["AI Integration", "Admin Interface", "Smart Routing"],
2069
+ "timestamp": "2024-01-15T10:30:00Z"
2070
+ }
2071
+ }
2072
+
2073
+ if '/ai/' in path:
2074
+ return {
2075
+ "model": "gpt-3.5-turbo",
2076
+ "response": "AI-generated response",
2077
+ "confidence": 0.95,
2078
+ "processing_time_ms": 250
2079
+ }
2080
+
2081
+ return examples.get(path, {"message": "Success", "data": {}})
2082
+
2083
+ def _generate_api_schemas(self) -> dict:
2084
+ """Generate API schemas for common data types"""
2085
+ return {
2086
+ "FrameworkInfo": {
2087
+ "type": "object",
2088
+ "properties": {
2089
+ "framework": {"type": "string", "example": "CREATESONLINE"},
2090
+ "version": {"type": "string", "example": self.version},
2091
+ "status": {"type": "string", "enum": ["operational", "maintenance", "error"]},
2092
+ "ai_enabled": {"type": "boolean"},
2093
+ "features": {"type": "array", "items": {"type": "string"}}
2094
+ }
2095
+ },
2096
+ "HealthStatus": {
2097
+ "type": "object",
2098
+ "properties": {
2099
+ "status": {"type": "string", "enum": ["healthy", "degraded", "unhealthy"]},
2100
+ "timestamp": {"type": "string", "format": "date-time"},
2101
+ "uptime": {"type": "integer", "description": "Uptime in seconds"},
2102
+ "system": {
2103
+ "type": "object",
2104
+ "properties": {
2105
+ "memory": {"type": "string"},
2106
+ "cpu": {"type": "string"},
2107
+ "disk": {"type": "string"}
2108
+ }
2109
+ }
2110
+ }
2111
+ },
2112
+ "Error": {
2113
+ "type": "object",
2114
+ "properties": {
2115
+ "error": {"type": "string"},
2116
+ "message": {"type": "string"},
2117
+ "code": {"type": "integer"},
2118
+ "timestamp": {"type": "string", "format": "date-time"}
2119
+ }
2120
+ }
2121
+ }
2122
+
2123
+ def _generate_error_page(self, status_code: int, error_message: str, path: str = "", method: str = "GET", details: str = "") -> str:
2124
+ """Generate beautiful HTML error pages matching homepage UI"""
2125
+
2126
+ error_titles = {
2127
+ 404: "Page Not Found",
2128
+ 500: "Internal Server Error",
2129
+ 403: "Access Forbidden",
2130
+ 400: "Bad Request"
2131
+ }
2132
+
2133
+ title = error_titles.get(status_code, f"Error {status_code}")
2134
+
2135
+ return f"""<!DOCTYPE html>
2136
+ <html lang="en">
2137
+ <head>
2138
+ <meta charset="UTF-8">
2139
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
2140
+ <title>{title} - CREATESONLINE</title>
2141
+ <style>
2142
+ * {{
2143
+ margin: 0;
2144
+ padding: 0;
2145
+ box-sizing: border-box;
2146
+ }}
2147
+
2148
+ body {{
2149
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
2150
+ background: #0a0a0a;
2151
+ color: #ffffff;
2152
+ padding: 40px 20px;
2153
+ min-height: 100vh;
2154
+ display: flex;
2155
+ align-items: center;
2156
+ justify-content: center;
2157
+ }}
2158
+
2159
+ .error-container {{
2160
+ max-width: 700px;
2161
+ width: 100%;
2162
+ background: #1a1a1a;
2163
+ padding: 60px 50px;
2164
+ border-radius: 12px;
2165
+ border: 1px solid #2a2a2a;
2166
+ text-align: center;
2167
+ }}
2168
+
2169
+ .error-code {{
2170
+ font-size: 8rem;
2171
+ font-weight: 700;
2172
+ background: linear-gradient(135deg, #ffffff 0%, #a0a0a0 100%);
2173
+ -webkit-background-clip: text;
2174
+ -webkit-text-fill-color: transparent;
2175
+ background-clip: text;
2176
+ margin-bottom: 20px;
2177
+ line-height: 1;
2178
+ }}
2179
+
2180
+ h1 {{
2181
+ font-size: 2em;
2182
+ font-weight: 600;
2183
+ margin-bottom: 15px;
2184
+ color: #fff;
2185
+ }}
2186
+
2187
+ p {{
2188
+ color: #888;
2189
+ font-size: 1.1em;
2190
+ margin-bottom: 40px;
2191
+ line-height: 1.6;
2192
+ }}
2193
+
2194
+ .btn {{
2195
+ padding: 14px 28px;
2196
+ background: #ffffff;
2197
+ color: #000;
2198
+ border-radius: 8px;
2199
+ text-decoration: none;
2200
+ font-weight: 600;
2201
+ transition: all 0.3s ease;
2202
+ display: inline-block;
2203
+ }}
2204
+
2205
+ .btn:hover {{
2206
+ background: #f0f0f0;
2207
+ transform: translateY(-2px);
2208
+ box-shadow: 0 8px 20px rgba(255, 255, 255, 0.15);
2209
+ }}
2210
+
2211
+ .footer {{
2212
+ margin-top: 50px;
2213
+ padding-top: 30px;
2214
+ border-top: 1px solid #2a2a2a;
2215
+ color: #666;
2216
+ font-size: 0.9em;
2217
+ }}
2218
+
2219
+ @media (max-width: 600px) {{
2220
+ .error-container {{
2221
+ padding: 40px 30px;
2222
+ }}
2223
+ .error-code {{
2224
+ font-size: 5em;
2225
+ }}
2226
+ h1 {{
2227
+ font-size: 1.5em;
2228
+ }}
2229
+ }}
2230
+ </style>
2231
+ </head>
2232
+ <body>
2233
+ <div class="error-container">
2234
+ <div class="error-code">{status_code}</div>
2235
+ <h1>{title}</h1>
2236
+ <p>{error_message}</p>
2237
+
2238
+ <a href="/" class="btn">Go Home</a>
2239
+
2240
+ <div class="footer">
2241
+ <p>CREATESONLINE v0.1.6</p>
2242
+ </div>
2243
+ </div>
2244
+ </body>
2245
+ </html>"""
2246
+
2247
+
2248
+ class CreatesonlineInternalRequest:
2249
+ """Internal request object for zero-dependency mode"""
2250
+
2251
+ def __init__(self, scope, receive):
2252
+ self.scope = scope
2253
+ self.receive = receive
2254
+ self.method = scope['method']
2255
+ self.url = self._build_url(scope)
2256
+ self.path = scope['path']
2257
+ self.query_params = self._parse_query_string(scope.get('query_string', b''))
2258
+ self.path_params = scope.get('path_params', {})
2259
+ self.headers = self._parse_headers(scope.get('headers', []))
2260
+
2261
+ def _build_url(self, scope):
2262
+ """Build URL object from scope"""
2263
+ scheme = scope.get('scheme', 'http')
2264
+ server = scope.get('server', ('localhost', 80))
2265
+ path = scope.get('path', '/')
2266
+ query_string = scope.get('query_string', b'').decode()
2267
+
2268
+ url = f"{scheme}://{server[0]}:{server[1]}{path}"
2269
+ if query_string:
2270
+ url += f"?{query_string}"
2271
+
2272
+ return url
2273
+
2274
+ def _parse_query_string(self, query_string):
2275
+ """Parse query string into dict"""
2276
+ if not query_string:
2277
+ return {}
2278
+
2279
+ return parse_qs(query_string.decode(), keep_blank_values=True)
2280
+
2281
+ def _parse_headers(self, headers):
2282
+ """Parse headers into dict"""
2283
+ header_dict = {}
2284
+ for name, value in headers:
2285
+ # Handle both bytes and string headers
2286
+ if isinstance(name, bytes):
2287
+ name = name.decode()
2288
+ if isinstance(value, bytes):
2289
+ value = value.decode()
2290
+ header_dict[name.lower()] = value
2291
+ return header_dict
2292
+
2293
+ async def json(self):
2294
+ """Parse JSON body"""
2295
+ body = await self._get_body()
2296
+ return json.loads(body.decode())
2297
+
2298
+ async def body(self):
2299
+ """Get raw body"""
2300
+ return await self._get_body()
2301
+
2302
+ async def _get_body(self):
2303
+ """Get request body"""
2304
+ body = b''
2305
+ while True:
2306
+ message = await self.receive()
2307
+ if message['type'] == 'http.request':
2308
+ body += message.get('body', b'')
2309
+ if not message.get('more_body', False):
2310
+ break
2311
+ return body
2312
+
2313
+ def _generate_error_page(self, status_code: int, error_message: str, path: str = "", method: str = "GET", details: str = "") -> str:
2314
+ """Generate beautiful HTML error pages with consistent CREATESONLINE theming"""
2315
+
2316
+ # Define error page content based on status code
2317
+ error_info = {
2318
+ 404: {
2319
+ "title": "Page Not Found",
2320
+ "emoji": "🔍",
2321
+ "description": "The page you're looking for doesn't exist or has been moved.",
2322
+ "suggestions": [
2323
+ "Check the URL for typos",
2324
+ "Go back to the homepage",
2325
+ "Browse our available API endpoints",
2326
+ "Contact support if you believe this is an error"
2327
+ ]
2328
+ },
2329
+ 500: {
2330
+ "title": "Internal Server Error",
2331
+ "emoji": "⚠️",
2332
+ "description": "Something went wrong on our end. We're working to fix it.",
2333
+ "suggestions": [
2334
+ "Try refreshing the page",
2335
+ "Wait a moment and try again",
2336
+ "Check our status page",
2337
+ "Contact support if the problem persists"
2338
+ ]
2339
+ },
2340
+ 403: {
2341
+ "title": "Access Forbidden",
2342
+ "emoji": "🚫",
2343
+ "description": "You don't have permission to access this resource.",
2344
+ "suggestions": [
2345
+ "Check if you're logged in",
2346
+ "Verify your permissions",
2347
+ "Contact an administrator",
2348
+ "Return to the homepage"
2349
+ ]
2350
+ },
2351
+ 400: {
2352
+ "title": "Bad Request",
2353
+ "emoji": "❌",
2354
+ "description": "The request was invalid or could not be processed.",
2355
+ "suggestions": [
2356
+ "Check your request format",
2357
+ "Review the API documentation",
2358
+ "Verify required parameters",
2359
+ "Try a different approach"
2360
+ ]
2361
+ }
2362
+ }
2363
+
2364
+ # Get error info or default for unknown status codes
2365
+ info = error_info.get(status_code, {
2366
+ "title": f"Error {status_code}",
2367
+ "emoji": "⚠️",
2368
+ "description": error_message or "An unexpected error occurred.",
2369
+ "suggestions": [
2370
+ "Try refreshing the page",
2371
+ "Go back to the previous page",
2372
+ "Contact support",
2373
+ "Return to the homepage"
2374
+ ]
2375
+ })
2376
+
2377
+ # Generate navigation suggestions based on available routes
2378
+ nav_links = []
2379
+ if hasattr(self, '_internal_routes'):
2380
+ for route_key in self._internal_routes.keys():
2381
+ route_method, route_path = route_key.split(':', 1)
2382
+ if route_method == 'GET' and not '{' in route_path: # Only GET routes without parameters
2383
+ if route_path in ['/', '/health', '/admin', '/docs']:
2384
+ route_name = {
2385
+ '/': 'Home',
2386
+ '/health': 'System Health',
2387
+ '/admin': 'Admin Panel',
2388
+ '/docs': 'API Documentation'
2389
+ }.get(route_path, route_path.title())
2390
+ nav_links.append(f'<a href="{route_path}" style="color: #ffffff; text-decoration: none; font-weight: 600; padding: 0.75rem 1.5rem; border-radius: 0.5rem; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); backdrop-filter: blur(10px); transition: all 0.2s ease; display: inline-block; margin: 0.5rem;">{route_name}</a>')
2391
+
2392
+ return f"""
2393
+ <!DOCTYPE html>
2394
+ <html lang="en">
2395
+ <head>
2396
+ <meta charset="UTF-8">
2397
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
2398
+ <title>{info['title']} - CREATESONLINE</title>
2399
+ <link rel="preconnect" href="https://fonts.googleapis.com">
2400
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
2401
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
2402
+ <link rel="icon" type="image/x-icon" href="/static/image/favicon.ico">
2403
+ <style>
2404
+ * {{ margin: 0; padding: 0; box-sizing: border-box; }}
2405
+
2406
+ @keyframes rotate-pulse {{
2407
+ 0% {{ transform: rotate(0deg) scale(1); }}
2408
+ 25% {{ transform: rotate(10deg) scale(1.1); }}
2409
+ 50% {{ transform: rotate(0deg) scale(1); }}
2410
+ 75% {{ transform: rotate(-10deg) scale(1.1); }}
2411
+ 100% {{ transform: rotate(0deg) scale(1); }}
2412
+ }}
2413
+
2414
+ @keyframes float {{
2415
+ 0%, 100% {{ transform: translateY(0px); }}
2416
+ 50% {{ transform: translateY(-20px); }}
2417
+ }}
2418
+
2419
+ body {{
2420
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
2421
+ background: #0a0a0a;
2422
+ color: #ffffff;
2423
+ padding: 40px 20px;
2424
+ min-height: 100vh;
2425
+ display: flex;
2426
+ align-items: center;
2427
+ justify-content: center;
2428
+ }}
2429
+
2430
+ .error-container {{
2431
+ max-width: 700px;
2432
+ width: 100%;
2433
+ background: #1a1a1a;
2434
+ padding: 60px 50px;
2435
+ border-radius: 12px;
2436
+ border: 1px solid #2a2a2a;
2437
+ text-align: center;
2438
+ }}
2439
+
2440
+ .error-icon {{
2441
+ font-size: 4rem;
2442
+ margin-bottom: 1.5rem;
2443
+ display: block;
2444
+ }}
2445
+
2446
+ .error-code {{
2447
+ font-size: 8rem;
2448
+ font-weight: 700;
2449
+ background: linear-gradient(135deg, #ffffff 0%, #a0a0a0 100%);
2450
+ -webkit-background-clip: text;
2451
+ -webkit-text-fill-color: transparent;
2452
+ background-clip: text;
2453
+ margin-bottom: 20px;
2454
+ line-height: 1;
2455
+ }}
2456
+
2457
+ .error-title {{
2458
+ font-size: 2em;
2459
+ font-weight: 600;
2460
+ margin-bottom: 15px;
2461
+ color: #fff;
2462
+ }}
2463
+
2464
+ .error-description {{
2465
+ color: #888;
2466
+ font-size: 1.1em;
2467
+ margin-bottom: 40px;
2468
+ line-height: 1.6;
2469
+ }}
2470
+
2471
+ .error-details {{
2472
+ background: #0a0a0a;
2473
+ border: 1px solid #2a2a2a;
2474
+ border-radius: 8px;
2475
+ padding: 20px;
2476
+ margin: 30px 0;
2477
+ text-align: left;
2478
+ }}
2479
+
2480
+ .error-details h4 {{
2481
+ color: #fff;
2482
+ margin-bottom: 15px;
2483
+ font-size: 1.1em;
2484
+ }}
2485
+
2486
+ .error-details p {{
2487
+ color: #888;
2488
+ font-size: 0.95em;
2489
+ margin: 8px 0;
2490
+ }}
2491
+
2492
+ .actions {{
2493
+ display: flex;
2494
+ gap: 15px;
2495
+ justify-content: center;
2496
+ flex-wrap: wrap;
2497
+ margin-top: 30px;
2498
+ }}
2499
+
2500
+ .btn {{
2501
+ padding: 14px 28px;
2502
+ border-radius: 8px;
2503
+ text-decoration: none;
2504
+ font-weight: 600;
2505
+ transition: all 0.3s ease;
2506
+ display: inline-block;
2507
+ }}
2508
+
2509
+ .btn-primary {{
2510
+ background: #ffffff;
2511
+ color: #000;
2512
+ }}
2513
+
2514
+ .btn-primary:hover {{
2515
+ background: #f0f0f0;
2516
+ transform: translateY(-2px);
2517
+ box-shadow: 0 8px 20px rgba(255, 255, 255, 0.15);
2518
+ }}
2519
+
2520
+ .footer {{
2521
+ margin-top: 50px;
2522
+ padding-top: 30px;
2523
+ border-top: 1px solid #2a2a2a;
2524
+ color: #666;
2525
+ font-size: 0.9em;
2526
+ }}
2527
+ color: #ffffff;
2528
+ opacity: 0.7;
2529
+ font-size: 0.9rem;
2530
+
2531
+ @media (max-width: 600px) {{
2532
+ .error-container {{
2533
+ padding: 40px 30px;
2534
+ }}
2535
+ .error-code {{
2536
+ font-size: 5em;
2537
+ }}
2538
+ .error-title {{
2539
+ font-size: 1.5em;
2540
+ }}
2541
+ .actions {{
2542
+ flex-direction: column;
2543
+ }}
2544
+ .btn {{
2545
+ width: 100%;
2546
+ }}
2547
+ }}
2548
+ </style>
2549
+ </head>
2550
+ <body>
2551
+ <div class="error-container">
2552
+ <div class="error-code">{status_code}</div>
2553
+ <h1 class="error-title">{info['title']}</h1>
2554
+ <p class="error-description">{info['description']}</p>
2555
+
2556
+ {f'''
2557
+ <div class="error-details">
2558
+ <h4>Request Details</h4>
2559
+ <p><strong>Path:</strong> {path}</p>
2560
+ <p><strong>Method:</strong> {method}</p>
2561
+ </div>
2562
+ ''' if path else ''}
2563
+
2564
+ <div class="actions">
2565
+ <a href="/" class="btn btn-primary">Go Home</a>
2566
+ </div>
2567
+
2568
+ <div class="footer">
2569
+ <p>CREATESONLINE v0.1.6 - AI-Native Web Framework</p>
2570
+ </div>
2571
+ </div>
2572
+ <img src="/static/image/favicon.ico" alt="CREATESONLINE" />
2573
+ <span>Powered by CREATESONLINE</span>
2574
+ </div>
2575
+ </body>
2576
+ </html>
2577
+ """