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
createsonline/app.py ADDED
@@ -0,0 +1,506 @@
1
+ # createsonline/app.py
2
+ """
3
+ CREATESONLINE Application Core
4
+
5
+ Main application class and request handling
6
+ """
7
+
8
+ import sys
9
+ import json
10
+ import hashlib
11
+ import logging
12
+ from datetime import datetime
13
+ from typing import Dict, Any, Optional, List, Callable, Union
14
+
15
+ # System requirements check
16
+ if sys.version_info < (3, 9):
17
+ raise RuntimeError(f"CREATESONLINE requires Python 3.9+. Current: {sys.version}")
18
+
19
+ # Setup logging
20
+ logger = logging.getLogger("createsonline")
21
+
22
+ # Get version
23
+ from . import __version__
24
+
25
+
26
+ class CreatesonlineInternalApp:
27
+ """
28
+ Pure CREATESONLINE core application - ZERO external dependencies
29
+
30
+ This is the internal implementation that works with just Python stdlib.
31
+ Provides full AI-native framework capabilities without any external packages.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ title: str = "CREATESONLINE Application",
37
+ description: str = "AI-powered application built with CREATESONLINE",
38
+ version: str = "1.0.0",
39
+ ai_config: Optional[Dict[str, Any]] = None,
40
+ debug: bool = False,
41
+ **kwargs
42
+ ):
43
+ # Core application metadata
44
+ self.title = title
45
+ self.description = description
46
+ self.version = version
47
+ self.debug = debug
48
+ self.ai_config = ai_config or {}
49
+
50
+ # Internal routing system
51
+ self.routes = {}
52
+ self.middleware = []
53
+ self.startup_handlers = []
54
+ self.shutdown_handlers = []
55
+
56
+ # AI-native features (internal implementations)
57
+ self.ai_enabled = True
58
+ self.ai_features = []
59
+ self.ai_services = CreatesonlineInternalAI()
60
+
61
+ # Setup framework routes
62
+ self._setup_framework_routes()
63
+
64
+ logger.info(f"CREATESONLINE v{__version__} initialized (Internal Core)")
65
+ logger.info(f"{self.title} - AI-Native Framework Ready")
66
+
67
+ def _setup_framework_routes(self):
68
+ """Setup built-in CREATESONLINE framework routes"""
69
+
70
+ @self.get("/health")
71
+ async def health_check(request):
72
+ return {
73
+ "status": "healthy",
74
+ "framework": "CREATESONLINE",
75
+ "version": __version__,
76
+ "timestamp": datetime.utcnow().isoformat()
77
+ }
78
+
79
+ # ========================================
80
+ # PURE ASGI IMPLEMENTATION
81
+ # ========================================
82
+
83
+ async def __call__(self, scope, receive, send):
84
+ """Pure ASGI interface - no external dependencies"""
85
+
86
+ if scope['type'] == 'http':
87
+ await self._handle_http(scope, receive, send)
88
+ elif scope['type'] == 'websocket':
89
+ await self._handle_websocket(scope, receive, send)
90
+
91
+ async def _handle_http(self, scope, receive, send):
92
+ """Handle HTTP requests with internal router"""
93
+
94
+ # On first request, discover routes from routes.py to override decorators
95
+ if getattr(self, '_needs_route_discovery', False):
96
+ try:
97
+ from .project_init import auto_discover_routes
98
+ auto_discover_routes(self)
99
+ self._needs_route_discovery = False
100
+ except Exception:
101
+ self._needs_route_discovery = False
102
+
103
+ path = scope['path']
104
+ method = scope['method']
105
+ route_key = f"{method}:{path}"
106
+
107
+ # Create internal request object
108
+ request = CreatesonlineInternalRequest(scope, receive)
109
+
110
+ try:
111
+ # Check for static files first (before routing)
112
+ if method == 'GET' and self._is_static_path(path):
113
+ print(f"[DEBUG] Static file detected: {path}")
114
+ await self._serve_static_file(path, send)
115
+ return
116
+ else:
117
+ if method == 'GET':
118
+ print(f"[DEBUG] Not a static path: {path}")
119
+
120
+ # Find matching route
121
+ if route_key in self.routes:
122
+ handler = self.routes[route_key]
123
+ response_data = await handler(request)
124
+ status = 200
125
+ else:
126
+ # 404 handler - check for custom not_found handler
127
+ not_found_handler = self.routes.get('not_found') or self.routes.get('GET /404')
128
+ if not_found_handler:
129
+ response_data = await not_found_handler(request)
130
+ status = 404
131
+ else:
132
+ # Default 404 response
133
+ response_data = {
134
+ "error": "Not Found",
135
+ "path": path,
136
+ "method": method,
137
+ "framework": "CREATESONLINE",
138
+ "available_routes": list(self.routes.keys())
139
+ }
140
+ status = 404
141
+
142
+ # Send response
143
+ if isinstance(response_data, dict):
144
+ await self._send_json_response(send, response_data, status=status)
145
+ else:
146
+ await self._send_text_response(send, str(response_data))
147
+
148
+ except Exception as e:
149
+ # Error handling - log the full traceback
150
+ logger.exception(f"Request handling error for {method} {path}")
151
+ error_data = {
152
+ "error": "Internal Server Error",
153
+ "message": str(e) if self.debug else "Something went wrong",
154
+ "framework": "CREATESONLINE"
155
+ }
156
+ await self._send_json_response(send, error_data, status=500)
157
+
158
+ async def _handle_websocket(self, scope, receive, send):
159
+ """Handle WebSocket connections with security measures"""
160
+ await send({'type': 'websocket.accept'})
161
+
162
+ message_count = 0
163
+ max_messages = 100
164
+
165
+ while True:
166
+ message = await receive()
167
+ if message['type'] == 'websocket.disconnect':
168
+ break
169
+ elif message['type'] == 'websocket.receive':
170
+ message_count += 1
171
+ if message_count > max_messages:
172
+ logger.warning("WebSocket rate limit exceeded")
173
+ await send({'type': 'websocket.close', 'code': 1008})
174
+ break
175
+
176
+ user_text = message.get('text', '')
177
+ if user_text:
178
+ logger.info(f"WebSocket message received (length: {len(user_text)})")
179
+
180
+ await send({
181
+ 'type': 'websocket.send',
182
+ 'text': json.dumps({
183
+ "framework": "CREATESONLINE",
184
+ "message": "WebSocket message processed",
185
+ "message_count": message_count
186
+ })
187
+ })
188
+
189
+ async def _send_json_response(self, send, data, status=200):
190
+ """Send JSON response"""
191
+ response_body = json.dumps(data, indent=2 if self.debug else None).encode('utf-8')
192
+
193
+ await send({
194
+ 'type': 'http.response.start',
195
+ 'status': status,
196
+ 'headers': [
197
+ [b'content-type', b'application/json'],
198
+ [b'content-length', str(len(response_body)).encode()],
199
+ [b'x-framework', b'CREATESONLINE'],
200
+ [b'x-version', __version__.encode()],
201
+ ],
202
+ })
203
+
204
+ await send({
205
+ 'type': 'http.response.body',
206
+ 'body': response_body,
207
+ })
208
+
209
+ async def _send_text_response(self, send, text, status=200):
210
+ """Send plain text or HTML response"""
211
+ response_body = text.encode('utf-8')
212
+
213
+ # Detect if it's HTML
214
+ content_type = b'text/html; charset=utf-8' if text.strip().startswith('<!DOCTYPE') or text.strip().startswith('<html') else b'text/plain'
215
+
216
+ await send({
217
+ 'type': 'http.response.start',
218
+ 'status': status,
219
+ 'headers': [
220
+ [b'content-type', content_type],
221
+ [b'content-length', str(len(response_body)).encode()],
222
+ [b'x-framework', b'CREATESONLINE'],
223
+ ],
224
+ })
225
+
226
+ await send({
227
+ 'type': 'http.response.body',
228
+ 'body': response_body,
229
+ })
230
+
231
+ def _is_static_path(self, path: str) -> bool:
232
+ """Check if path is a static file request"""
233
+ static_prefixes = ['/static/', '/css/', '/js/', '/images/', '/img/', '/assets/', '/media/', '/icons/']
234
+ static_extensions = {'.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.webp',
235
+ '.woff', '.woff2', '.ttf', '.eot', '.pdf', '.txt', '.json', '.xml'}
236
+
237
+ for prefix in static_prefixes:
238
+ if path.startswith(prefix):
239
+ return True
240
+
241
+ for ext in static_extensions:
242
+ if path.endswith(ext):
243
+ return True
244
+
245
+ return False
246
+
247
+ async def _serve_static_file(self, path, send):
248
+ """Serve static files using StaticFileHandler"""
249
+ try:
250
+ print(f"[DEBUG] _serve_static_file called with: {path}")
251
+ logger.info(f"=== SERVING STATIC FILE: {path} ===")
252
+ from .static_files import static_handler
253
+
254
+ print(f"[DEBUG] Static dirs: {[str(d) for d in static_handler.static_dirs]}")
255
+ logger.info(f"Static dirs: {[str(d) for d in static_handler.static_dirs]}")
256
+ content, status_code, headers = static_handler.serve_file(path)
257
+ print(f"[DEBUG] serve_file returned: status={status_code}, content_length={len(content)}")
258
+ logger.info(f"Result: status={status_code}, content_length={len(content)}")
259
+
260
+ header_list = [[k.encode() if isinstance(k, str) else k,
261
+ v.encode() if isinstance(v, str) else v]
262
+ for k, v in headers.items()]
263
+
264
+ header_list.append([b'x-framework', b'CREATESONLINE'])
265
+
266
+ await send({
267
+ 'type': 'http.response.start',
268
+ 'status': status_code,
269
+ 'headers': header_list,
270
+ })
271
+
272
+ await send({
273
+ 'type': 'http.response.body',
274
+ 'body': content if isinstance(content, bytes) else content.encode('utf-8'),
275
+ })
276
+
277
+ except Exception as e:
278
+ logger.error(f"Error serving static file {path}: {e}")
279
+ import traceback
280
+ traceback.print_exc()
281
+ await self._send_json_response(send, {"error": "Static file error", "message": str(e)}, status=500)
282
+
283
+ # ========================================
284
+ # ROUTING DECORATORS
285
+ # ========================================
286
+
287
+ def get(self, path: str):
288
+ """GET route decorator"""
289
+ def decorator(func):
290
+ self.routes[f"GET:{path}"] = func
291
+ return func
292
+ return decorator
293
+
294
+ def post(self, path: str):
295
+ """POST route decorator"""
296
+ def decorator(func):
297
+ self.routes[f"POST:{path}"] = func
298
+ return func
299
+ return decorator
300
+
301
+ def put(self, path: str):
302
+ """PUT route decorator"""
303
+ def decorator(func):
304
+ self.routes[f"PUT:{path}"] = func
305
+ return func
306
+ return decorator
307
+
308
+ def delete(self, path: str):
309
+ """DELETE route decorator"""
310
+ def decorator(func):
311
+ self.routes[f"DELETE:{path}"] = func
312
+ return func
313
+ return decorator
314
+
315
+ def route(self, path: str, methods: List[str] = None):
316
+ """Multi-method route decorator"""
317
+ if methods is None:
318
+ methods = ["GET"]
319
+
320
+ def decorator(func):
321
+ for method in methods:
322
+ self.routes[f"{method.upper()}:{path}"] = func
323
+ return func
324
+ return decorator
325
+
326
+ # ========================================
327
+ # AI-NATIVE FEATURES
328
+ # ========================================
329
+
330
+ def enable_ai_features(self, features: List[str]):
331
+ """Enable AI features"""
332
+ for feature in features:
333
+ if feature not in self.ai_features:
334
+ self.ai_features.append(feature)
335
+ logger.info(f"AI Feature enabled: {feature}")
336
+ return self
337
+
338
+ # ========================================
339
+ # LIFECYCLE EVENTS
340
+ # ========================================
341
+
342
+ def on_startup(self, func: Callable):
343
+ """Register startup handler"""
344
+ self.startup_handlers.append(func)
345
+ return func
346
+
347
+ def on_shutdown(self, func: Callable):
348
+ """Register shutdown handler"""
349
+ self.shutdown_handlers.append(func)
350
+ return func
351
+
352
+ # ========================================
353
+ # SERVER RUNNER
354
+ # ========================================
355
+
356
+ def run(self, host: str = "127.0.0.1", port: int = 8000, reload: bool = False):
357
+ """Run the application"""
358
+ from .server import run_server
359
+
360
+ logger.info("Starting CREATESONLINE Pure Python Server")
361
+ logger.info(f"Framework: CREATESONLINE v{__version__}")
362
+ run_server(self, host=host, port=port, reload=reload)
363
+
364
+
365
+ class CreatesonlineInternalRequest:
366
+ """Internal request object"""
367
+
368
+ def __init__(self, scope, receive):
369
+ self.scope = scope
370
+ self.receive = receive
371
+ self.path = scope['path']
372
+ self.method = scope['method']
373
+ self.headers = dict(scope.get('headers', []))
374
+ self.query_params = self._parse_query_string(scope.get('query_string', b''))
375
+ self.path_params = scope.get('path_params', {})
376
+
377
+ def _parse_query_string(self, query_string):
378
+ """Parse query string into dict"""
379
+ if not query_string:
380
+ return {}
381
+
382
+ params = {}
383
+ for pair in query_string.decode().split('&'):
384
+ if '=' in pair:
385
+ key, value = pair.split('=', 1)
386
+ params[key] = value
387
+ return params
388
+
389
+ async def json(self):
390
+ """Parse JSON body"""
391
+ body = await self._get_body()
392
+ return json.loads(body.decode())
393
+
394
+ async def _get_body(self):
395
+ """Get request body"""
396
+ body = b''
397
+ while True:
398
+ message = await self.receive()
399
+ if message['type'] == 'http.request':
400
+ body += message.get('body', b'')
401
+ if not message.get('more_body', False):
402
+ break
403
+ return body
404
+
405
+
406
+ class CreatesonlineInternalAI:
407
+ """Internal AI services"""
408
+
409
+ def __init__(self):
410
+ self.cache = {}
411
+
412
+ async def generate_text(self, prompt: str, **kwargs) -> str:
413
+ """Generate text using internal algorithms"""
414
+ templates = {
415
+ "hello": "Hello! Welcome to CREATESONLINE - the AI-Native framework.",
416
+ "describe": f"CREATESONLINE is an innovative AI-native web framework.",
417
+ }
418
+
419
+ prompt_lower = prompt.lower()
420
+ for key, template in templates.items():
421
+ if key in prompt_lower:
422
+ return template
423
+
424
+ return f"CREATESONLINE AI Response: Generated content for '{prompt[:50]}...'"
425
+
426
+ def get_embedding(self, text: str, dimensions: int = 128) -> List[float]:
427
+ """Generate hash-based embeddings"""
428
+ hash_obj = hashlib.md5(text.encode())
429
+ hash_bytes = hash_obj.digest()
430
+
431
+ embedding = []
432
+ for i in range(dimensions):
433
+ byte_index = i % len(hash_bytes)
434
+ value = (hash_bytes[byte_index] / 255.0) - 0.5
435
+ embedding.append(value)
436
+
437
+ return embedding
438
+
439
+
440
+ # ========================================
441
+ # MAIN FRAMEWORK API
442
+ # ========================================
443
+
444
+ def create_app(
445
+ title: str = "CREATESONLINE Application",
446
+ description: str = "AI-powered application built with CREATESONLINE",
447
+ version: str = "1.0.0",
448
+ ai_config: Optional[Dict[str, Any]] = None,
449
+ debug: bool = False,
450
+ auto_init: bool = True,
451
+ **kwargs
452
+ ) -> CreatesonlineInternalApp:
453
+ """Create a CREATESONLINE application instance
454
+
455
+ Args:
456
+ title: Application title
457
+ description: Application description
458
+ version: Application version
459
+ ai_config: AI configuration dictionary
460
+ debug: Enable debug mode
461
+ auto_init: Automatically initialize project structure if needed (default: True)
462
+ **kwargs: Additional configuration
463
+ """
464
+
465
+ # Auto-initialize project structure if needed (silent)
466
+ if auto_init:
467
+ try:
468
+ from .project_init import init_project_if_needed
469
+ init_project_if_needed(verbose=False) # Silent initialization
470
+ except Exception:
471
+ pass # Silent failure - don't break app startup
472
+
473
+ # TRY: Use full-featured app if available
474
+ try:
475
+ from createsonline.config.app import CreatesonlineApp
476
+ logger.info("Loading full-featured CREATESONLINE...")
477
+ app_instance = CreatesonlineApp(
478
+ title=title,
479
+ description=description,
480
+ version=version,
481
+ ai_config=ai_config or {},
482
+ debug=debug,
483
+ **kwargs
484
+ )
485
+ except ImportError:
486
+ # FALLBACK: Use internal core
487
+ logger.info("Using CREATESONLINE Internal Core")
488
+ app_instance = CreatesonlineInternalApp(
489
+ title=title,
490
+ description=description,
491
+ version=version,
492
+ ai_config=ai_config or {},
493
+ debug=debug,
494
+ **kwargs
495
+ )
496
+
497
+ # Auto-discover and register routes from routes.py (if exists)
498
+ # DEFERRED: Will be applied at first request to override any @app.get decorators
499
+ if auto_init:
500
+ try:
501
+ # Store the app instance for deferred route loading
502
+ app_instance._needs_route_discovery = True
503
+ except Exception:
504
+ pass
505
+
506
+ return app_instance
@@ -0,0 +1,8 @@
1
+ # createsonline/auth/__init__.py
2
+ """
3
+ CREATESONLINE Authentication System
4
+ """
5
+
6
+ from .models import User, Group, Permission, hash_password, verify_password
7
+
8
+ __all__ = ['User', 'Group', 'Permission', 'hash_password', 'verify_password']