skeleton-framework 0.1.0__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 (93) hide show
  1. skeleton/__init__.py +0 -0
  2. skeleton/cli.py +151 -0
  3. skeleton/client.py +269 -0
  4. skeleton/infrastructure/__init__.py +1 -0
  5. skeleton/infrastructure/bootstrap/__init__.py +0 -0
  6. skeleton/infrastructure/bootstrap/src/__init__.py +0 -0
  7. skeleton/infrastructure/bootstrap/src/commands/__init__.py +0 -0
  8. skeleton/infrastructure/bootstrap/src/commands/client/__init__.py +0 -0
  9. skeleton/infrastructure/bootstrap/src/commands/client/init.py +486 -0
  10. skeleton/infrastructure/bootstrap/src/commands/client/install.py +113 -0
  11. skeleton/infrastructure/bootstrap/src/commands/dev/__init__.py +0 -0
  12. skeleton/infrastructure/bootstrap/src/commands/dev/build.py +80 -0
  13. skeleton/infrastructure/bootstrap/src/commands/dev/init.py +80 -0
  14. skeleton/infrastructure/bootstrap/src/commands/dev/install.py +168 -0
  15. skeleton/infrastructure/bootstrap/src/commands/dev/pack.py +55 -0
  16. skeleton/infrastructure/bootstrap/src/config.py +54 -0
  17. skeleton/infrastructure/bootstrap/src/copy.py +56 -0
  18. skeleton/infrastructure/bootstrap/src/load.py +221 -0
  19. skeleton/infrastructure/bootstrap/src/templates/app/backend/requirements.txt +1 -0
  20. skeleton/infrastructure/bootstrap/src/templates/app/backend/routes.json +10 -0
  21. skeleton/infrastructure/bootstrap/src/templates/app/backend/src/__init__.py +0 -0
  22. skeleton/infrastructure/bootstrap/src/templates/app/backend/src/main.py +35 -0
  23. skeleton/infrastructure/bootstrap/src/templates/app/frontend/package.json +21 -0
  24. skeleton/infrastructure/bootstrap/src/templates/app/frontend/skeleton-config.json +29 -0
  25. skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/index.html +16 -0
  26. skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/main.tsx +15 -0
  27. skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/static/css/styles.css +28 -0
  28. skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/static/img/skeleton.png +0 -0
  29. skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/static/js/script.js +1 -0
  30. skeleton/infrastructure/bootstrap/src/templates/app/frontend/tsconfig.json +90 -0
  31. skeleton/infrastructure/bootstrap/src/templates/config/.gitignore +21 -0
  32. skeleton/infrastructure/bootstrap/src/templates/config/skeleton-dependencies.json +21 -0
  33. skeleton/infrastructure/bootstrap/src/templates/config/skeleton-layout.json +11 -0
  34. skeleton/infrastructure/bootstrap/src/templates/config/skeleton-schemas.json +20 -0
  35. skeleton/infrastructure/bootstrap/src/templates/config/skeleton-servers.json +16 -0
  36. skeleton/infrastructure/common/__init__.py +1 -0
  37. skeleton/infrastructure/common/config.json +8 -0
  38. skeleton/infrastructure/common/src/__init__.py +0 -0
  39. skeleton/infrastructure/common/src/config.py +37 -0
  40. skeleton/infrastructure/common/src/constants.py +4 -0
  41. skeleton/infrastructure/common/src/context.py +15 -0
  42. skeleton/infrastructure/common/src/env.py +12 -0
  43. skeleton/infrastructure/common/src/layout.py +68 -0
  44. skeleton/infrastructure/common/src/loader.py +8 -0
  45. skeleton/infrastructure/common/src/repository.py +12 -0
  46. skeleton/infrastructure/common/src/utils.py +26 -0
  47. skeleton/infrastructure/gateway/__init__.py +0 -0
  48. skeleton/infrastructure/gateway/settings/proxy.json +24 -0
  49. skeleton/infrastructure/gateway/settings/services.json +10 -0
  50. skeleton/infrastructure/gateway/src/__init__.py +0 -0
  51. skeleton/infrastructure/gateway/src/app.py +98 -0
  52. skeleton/infrastructure/gateway/src/client.py +68 -0
  53. skeleton/infrastructure/gateway/src/config.py +29 -0
  54. skeleton/infrastructure/gateway/src/context.py +31 -0
  55. skeleton/infrastructure/gateway/src/headers.py +17 -0
  56. skeleton/infrastructure/gateway/src/lifespan.py +17 -0
  57. skeleton/infrastructure/gateway/src/loader.py +113 -0
  58. skeleton/infrastructure/gateway/src/logging.py +37 -0
  59. skeleton/infrastructure/gateway/src/main.py +139 -0
  60. skeleton/infrastructure/gateway/src/parser.py +59 -0
  61. skeleton/infrastructure/gateway/src/registry.py +30 -0
  62. skeleton/infrastructure/gateway/src/reverseproxy.py +54 -0
  63. skeleton/infrastructure/gateway/src/router.py +74 -0
  64. skeleton/infrastructure/gateway/src/schemas.py +21 -0
  65. skeleton/infrastructure/gateway/src/service.py +123 -0
  66. skeleton/infrastructure/gateway/src/utils.py +48 -0
  67. skeleton/infrastructure/gateway/src/validation.py +89 -0
  68. skeleton/infrastructure/layout.json +12 -0
  69. skeleton/infrastructure/runners/__init__.py +0 -0
  70. skeleton/infrastructure/runners/src/__init__.py +0 -0
  71. skeleton/infrastructure/runners/src/actions.py +4 -0
  72. skeleton/infrastructure/runners/src/browser.py +18 -0
  73. skeleton/infrastructure/runners/src/cmd.py +7 -0
  74. skeleton/infrastructure/runners/src/command.py +7 -0
  75. skeleton/infrastructure/runners/src/frontend.py +35 -0
  76. skeleton/infrastructure/runners/src/gateway.py +104 -0
  77. skeleton/infrastructure/runners/src/hook.py +53 -0
  78. skeleton/infrastructure/runners/src/main.py +78 -0
  79. skeleton/infrastructure/runners/src/packages.py +35 -0
  80. skeleton/infrastructure/runners/src/parser.py +84 -0
  81. skeleton/infrastructure/runners/src/process.py +99 -0
  82. skeleton/infrastructure/runners/src/services.py +16 -0
  83. skeleton/infrastructure/runners/src/utils.py +6 -0
  84. skeleton/infrastructure/runners/src/validation.py +28 -0
  85. skeleton/packages/.skeleton/skeleton-cli-1.0.0.tgz +0 -0
  86. skeleton/packages/.skeleton/skeleton-webpack-1.0.0.tgz +0 -0
  87. skeleton/root.py +234 -0
  88. skeleton_framework-0.1.0.dist-info/METADATA +440 -0
  89. skeleton_framework-0.1.0.dist-info/RECORD +93 -0
  90. skeleton_framework-0.1.0.dist-info/WHEEL +5 -0
  91. skeleton_framework-0.1.0.dist-info/entry_points.txt +2 -0
  92. skeleton_framework-0.1.0.dist-info/licenses/LICENSE +146 -0
  93. skeleton_framework-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,29 @@
1
+ {
2
+ "entry": {
3
+ "main": "main",
4
+ "index": "index"
5
+ },
6
+ "lib": {
7
+ "src": "src",
8
+ "dist": "dist",
9
+ "static": "static"
10
+ },
11
+ "devServer": {
12
+ "open": false,
13
+ "historyApiFallback": true,
14
+ "host": "127.0.0.1",
15
+ "port": 80,
16
+ "hot": true,
17
+ "overlay": true
18
+ },
19
+ "proxy": {
20
+ "on": false,
21
+ "host": "127.0.0.1",
22
+ "port": 8888,
23
+ "changeOrigin": true,
24
+ "secure": false
25
+ },
26
+ "tsconfig": {
27
+ "configFile": "./tsconfig.json"
28
+ }
29
+ }
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+
8
+ <title>Skeleton</title>
9
+
10
+ <link
11
+ rel="icon"
12
+ type="image/x-icon"
13
+ href="/static/img/skeleton.png"
14
+ >
15
+ </head>
16
+ </html>
@@ -0,0 +1,15 @@
1
+ import { createRoot } from "react-dom/client";
2
+
3
+ const body = document.querySelector("body");
4
+
5
+ if (!body) {
6
+ throw new Error("Body element not found");
7
+ }
8
+
9
+ const root = document.createElement("div");
10
+
11
+ body.appendChild(root);
12
+
13
+ createRoot(root).render(
14
+ <h1>Skeleton + FastAPI + React + WebPack</h1>
15
+ );
@@ -0,0 +1,28 @@
1
+ /*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*/
2
+
3
+ /*
4
+ disregard ANY/ALL padding, margin
5
+ & border when computing width/height
6
+ */
7
+
8
+ * {
9
+ box-sizing: border-box;
10
+ }
11
+
12
+ body, html {
13
+ height: 100vh;
14
+ }
15
+
16
+ #root {
17
+ min-height: 100vh;
18
+ }
19
+
20
+ .demo {
21
+ background-color: red;
22
+ }
23
+
24
+ .alt {
25
+ background-color: blue;
26
+ }
27
+
28
+ /*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*/
@@ -0,0 +1 @@
1
+ console.log("@scripts/script.js");
@@ -0,0 +1,90 @@
1
+ {
2
+ "compilerOptions": {
3
+
4
+ /* use modern automatic JSX transform! */
5
+ "jsx": "react-jsx",
6
+
7
+ "target": "ES2022", // emit as-is
8
+ "module": "ES2022", // modern import/export syntax
9
+
10
+ /**
11
+ * Using a bundler, like webpack or vite!
12
+ * Don't treat module imports like node!
13
+ * Consume ESM packages like @skeleton/core
14
+ * Enable extensionless imports!
15
+ */
16
+ "moduleResolution": "bundler",
17
+
18
+ /** Declare which global API's exit in env! */
19
+ "lib": ["DOM", "ES2022"],
20
+
21
+ /*
22
+ * save information about project graph from last compilation by detecting
23
+ * smallest set of files to re-emit instead of recompiling the entire project,
24
+ * enabling significantly faster subsequent builds by caching metadata
25
+ * This generates a .tsbuildinfo file (add to .gitignore!)
26
+ */
27
+ "incremental": true,
28
+
29
+ /**
30
+ * Fix module compatibility between
31
+ * CommonJS (require) & ES Modules (import)
32
+ */
33
+ // "esModuleInterop": true,
34
+
35
+ /**
36
+ * enable imports like ./config.json
37
+ */
38
+ "resolveJsonModule": true,
39
+
40
+ /**
41
+ * Each file to be compiled independently!
42
+ */
43
+ "isolatedModules": true,
44
+
45
+ /* webpack handles build! */
46
+ "noEmit": true,
47
+ "noEmitOnError": true,
48
+ "sourceMap": true,
49
+
50
+ /**
51
+ * skip type checking .d.ts files in node_modules
52
+ * Many packages have imperfect/conflicting/legacy types!
53
+ */
54
+ "skipLibCheck": true,
55
+
56
+ "strict": true,
57
+ "noImplicitAny": true,
58
+ // "noUnusedLocals": true,
59
+ "noImplicitReturns": true,
60
+ // "noUnusedParameters": true,
61
+
62
+ "forceConsistentCasingInFileNames": true,
63
+ // "disableSourceOfProjectReferenceRedirect": true,
64
+
65
+ "removeComments": true,
66
+
67
+ /**
68
+ * Decorators & typescript metadata!
69
+ */
70
+ /* @decorator/annotation syntax */
71
+ "experimentalDecorators": true,
72
+ "emitDecoratorMetadata": true,
73
+ // "useDefineForClassFields": true,
74
+
75
+ /* uses tsconfig-paths-webpack-plugin */
76
+ "paths": {
77
+
78
+ // common aliases!
79
+ "@styles/*": ["./src/static/css/*"],
80
+ "@scripts/*": ["./src/static/js/*"],
81
+ "@img/*": ["./src/static/img/*"],
82
+ },
83
+ },
84
+
85
+ "include": ["./src/**/*",],
86
+ "exclude": [
87
+ "dist",
88
+ "node_modules"
89
+ ],
90
+ }
@@ -0,0 +1,21 @@
1
+ # Skeleton local package artifacts
2
+ .skeleton/
3
+
4
+ # node, js, ts & webpack
5
+ node_modules/
6
+ dist/
7
+ build/
8
+ coverage/
9
+ *.tsbuildinfo
10
+
11
+ # Python
12
+ __pycache__/
13
+ .mypy_cache/
14
+ *.pyc
15
+ .venv/
16
+ venv/
17
+ env/
18
+
19
+ # misc
20
+ .DS_Store
21
+ .vscode
@@ -0,0 +1,21 @@
1
+ {
2
+ "frontend": {
3
+ "packages": {
4
+ "dependencies": {
5
+ "react": "^19.3.1",
6
+ "react-dom": "^19.3.1"
7
+ },
8
+ "devDependencies": {
9
+ "@types/react": "^19.3.0",
10
+ "@types/react-dom": "^19.3.0"
11
+ }
12
+ }
13
+ },
14
+ "backend": {
15
+ "requirements": {
16
+ "uvicorn": ">=0.34,<1.0",
17
+ "pydantic": ">=2.10,<3.0",
18
+ "sqlalchemy": ">=2.0,<2.1"
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "project": {
3
+ "app": "app"
4
+ },
5
+ "frontend": {
6
+ "directory": "frontend"
7
+ },
8
+ "backend": {
9
+ "directory": "backend"
10
+ }
11
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "schemas": {
3
+ "http": {
4
+ "backend": {
5
+ "prefix": "/api",
6
+ "strip": true
7
+ },
8
+ "frontend": {
9
+ "prefix": "/",
10
+ "strip": false
11
+ }
12
+ },
13
+ "ws": {
14
+ "backend": {
15
+ "prefix": "/ws",
16
+ "strip": true
17
+ }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "servers": {
3
+ "backend": {
4
+ "host": "127.0.0.1",
5
+ "port": 8080
6
+ },
7
+ "frontend": {
8
+ "host": "127.0.0.1",
9
+ "port": 3000
10
+ },
11
+ "gateway": {
12
+ "host": "127.0.0.1",
13
+ "port": 8000
14
+ }
15
+ }
16
+ }
@@ -0,0 +1 @@
1
+ from skeleton.infrastructure.common import *
@@ -0,0 +1,8 @@
1
+ {
2
+ "config": {
3
+ "servers": "skeleton-servers.json",
4
+ "schemas": "skeleton-schemas.json",
5
+ "proxy": "skeleton/infrastructure/gateway/settings/proxy.json",
6
+ "services": "skeleton/infrastructure/gateway/settings/services.json"
7
+ }
8
+ }
File without changes
@@ -0,0 +1,37 @@
1
+ from pathlib import Path
2
+
3
+ from skeleton.infrastructure.common.src.loader import load
4
+ from skeleton.infrastructure.common.src.layout import ProjectLayout
5
+ from skeleton.infrastructure.common.src.repository import ConfigRepository
6
+
7
+ def load_runtime_config(
8
+ path: Path,
9
+ project_root: Path,
10
+ framework_root: Path,
11
+ layout: ProjectLayout,
12
+ ) -> ConfigRepository:
13
+
14
+ CONFIG = load(path)["config"]
15
+
16
+ data: dict = {}
17
+
18
+ for name, config in CONFIG.items():
19
+
20
+ root = (
21
+ project_root
22
+ if name in ("servers", "schemas")
23
+ else framework_root
24
+ )
25
+
26
+ data[name] = load(root / config)
27
+
28
+ frontend_config = layout.frontend / "skeleton-config.json"
29
+ data["frontend"] = load(frontend_config)
30
+
31
+ return ConfigRepository(
32
+ servers=data["servers"],
33
+ schemas=data["schemas"],
34
+ frontend=data["frontend"],
35
+ proxy=data["proxy"],
36
+ services=data["services"],
37
+ )
@@ -0,0 +1,4 @@
1
+ class Bootstrap:
2
+ LAYOUT: str = "skeleton-layout.json"
3
+ GATEWAY_MODULE: str = "skeleton.infrastructure.gateway.src.main"
4
+ CONFIG_FILE_EXT = "config.json"
@@ -0,0 +1,15 @@
1
+ from pathlib import Path
2
+ from dataclasses import dataclass
3
+
4
+ from skeleton.infrastructure.common.src.layout import ProjectLayout
5
+ from skeleton.infrastructure.common.src.repository import ConfigRepository
6
+
7
+ @dataclass(frozen=True, kw_only=True)
8
+ class RuntimeContext:
9
+ root: Path
10
+ mode: str
11
+ args: list[str]
12
+ env: dict[str, str]
13
+ options: dict[str, str | bool]
14
+ config: ConfigRepository
15
+ layout: ProjectLayout
@@ -0,0 +1,12 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ def build_env(ROOT: Path, MODE: str):
5
+ base_env = os.environ.copy()
6
+ runtime_env = {
7
+ "APP_MODE": MODE,
8
+ "APP_ROOT": str(ROOT),
9
+ "PYTHONPATH": str(ROOT),
10
+ }
11
+ env = base_env | runtime_env
12
+ return env
@@ -0,0 +1,68 @@
1
+ import json
2
+
3
+ from pathlib import Path
4
+ from dataclasses import dataclass
5
+
6
+ @dataclass(frozen=True, kw_only=True)
7
+ class ProjectLayout:
8
+ frontend: Path
9
+ backend: Path
10
+ infrastructure: Path
11
+ gateway: Path
12
+ runners: Path
13
+ common: Path
14
+ packages: Path
15
+
16
+ def build_layout(
17
+ path: Path,
18
+ project_root: Path,
19
+ framework_root: Path,
20
+ ) -> ProjectLayout:
21
+
22
+ if not path.is_file():
23
+ raise FileNotFoundError(
24
+ f"Project layout configuration not found: {path}"
25
+ )
26
+
27
+ with path.open("r", encoding="utf-8") as file:
28
+ config = json.load(file)
29
+
30
+ try:
31
+ frontend = config["frontend"]["directory"]
32
+ backend = config["backend"]["directory"]
33
+
34
+ except (KeyError, TypeError) as error:
35
+ raise ValueError(
36
+ f"Invalid project layout configuration: {path}"
37
+ ) from error
38
+
39
+ for key, value in {
40
+ "frontend.directory": frontend,
41
+ "backend.directory": backend,
42
+ }.items():
43
+
44
+ if (
45
+ not isinstance(value, str)
46
+ or not value.strip()
47
+ or Path(value).is_absolute()
48
+ or len(Path(value).parts) != 1
49
+ or value in (".", "..")
50
+ ):
51
+ raise ValueError(
52
+ f"Invalid directory name for '{key}': {value!r}"
53
+ )
54
+
55
+ project_root = project_root.resolve()
56
+ framework_root = framework_root.resolve()
57
+
58
+ infrastructure = framework_root / "skeleton" / "infrastructure"
59
+
60
+ return ProjectLayout(
61
+ frontend=project_root / frontend,
62
+ backend=project_root / backend,
63
+ infrastructure=infrastructure,
64
+ gateway=infrastructure / "gateway",
65
+ runners=infrastructure / "runners",
66
+ common=infrastructure / "common",
67
+ packages=framework_root / "skeleton" / "packages",
68
+ )
@@ -0,0 +1,8 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ # json.load wrapper utility!
5
+ def load(path: Path) -> dict:
6
+ with open(path, "r", encoding="utf-8") as config:
7
+ data = json.load(config)
8
+ return data
@@ -0,0 +1,12 @@
1
+ from dataclasses import dataclass
2
+
3
+ # come back to this, to ensure only
4
+ # load what's needed in each layer
5
+ # store runtime/boostrap confiugration settings!
6
+ @dataclass(frozen=True, kw_only=True)
7
+ class ConfigRepository:
8
+ servers: dict # only gateway
9
+ schemas: dict # only gateway
10
+ frontend: dict # only gateway
11
+ proxy: dict # only gateway
12
+ services: dict # only gateway
@@ -0,0 +1,26 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ def resolve_executable_path(path) -> Path:
5
+ if os.name == "nt":
6
+ return Path(path)/".venv"/"Scripts"/"python.exe"
7
+ else:
8
+ return Path(path)/".venv"/"bin"/"python"
9
+
10
+ def check_file_exists(filename: str, path: Path):
11
+
12
+ if not path.exists():
13
+ raise FileNotFoundError(
14
+ f"{filename}: file does not exist {path}"
15
+ )
16
+
17
+ if not path.is_file():
18
+ raise IsADirectoryError(
19
+ f"{filename}: path is not a file {path}"
20
+ )
21
+
22
+ def module_to_path(module: str) -> Path:
23
+ return Path(module.replace(".", "/")).with_suffix(".py")
24
+
25
+ def path_to_module(path: Path) -> str:
26
+ return ".".join(path.with_suffix("").parts)
File without changes
@@ -0,0 +1,24 @@
1
+ {
2
+ "settings": {
3
+ "defaultTimeout": 15.0,
4
+ "followRedirects": false
5
+ },
6
+
7
+ "cors": {
8
+ "allowOrigins": [
9
+ "http://localhost:8000",
10
+ "http://127.0.0.1:8000",
11
+ "http://localhost:3000",
12
+ "http://127.0.0.1:3000"
13
+ ],
14
+ "allowCredentials": true,
15
+ "allowMethods": ["*"],
16
+ "allowHeaders": ["*"]
17
+ },
18
+
19
+ "methods": [
20
+ "GET", "POST", "PUT",
21
+ "PATCH", "DELETE", "HEAD",
22
+ "OPTIONS"
23
+ ]
24
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "services": {
3
+ "backend": {
4
+ "name": "app",
5
+ "ext": [".py", ".json"],
6
+ "reload": true,
7
+ "docs": "docs"
8
+ }
9
+ }
10
+ }
File without changes
@@ -0,0 +1,98 @@
1
+ from uuid import uuid4
2
+
3
+ from fastapi import FastAPI, Request
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+ from fastapi.responses import JSONResponse
6
+
7
+ from skeleton.infrastructure.common.src.context import RuntimeContext
8
+
9
+ from skeleton.infrastructure.gateway.src.router import ProxyRouter
10
+ from skeleton.infrastructure.gateway.src.client import ProxyClient
11
+ from skeleton.infrastructure.gateway.src.reverseproxy import ReverseProxy
12
+ from skeleton.infrastructure.gateway.src.lifespan import HTTPAsyncClientManager
13
+
14
+ from contextlib import asynccontextmanager
15
+
16
+ from skeleton.infrastructure.gateway.src.utils import build_static_dir
17
+
18
+ def create_app(context: RuntimeContext) -> FastAPI:
19
+
20
+ # print(context.config.frontend["lib"]["static"])
21
+ http = HTTPAsyncClientManager(
22
+ context.config.proxy["settings"]
23
+ )
24
+
25
+ @asynccontextmanager
26
+ async def lifespan(app: FastAPI):
27
+ await http.startup()
28
+ yield
29
+ await http.shutdown()
30
+
31
+ reverseproxy = FastAPI(
32
+ # name="Reverse Proxy Dev Gateway",
33
+ title="Reverse Proxy Dev Gateway",
34
+ description="Reverse Proxy Dev Gateway",
35
+ version="1.0.0",
36
+ lifespan=lifespan,
37
+ swagger_ui_parameters={
38
+ "docExpansion": "none",
39
+ "displayRequestDuration": True,
40
+ "defaultModelsExpandDepth": -1
41
+ },
42
+ )
43
+
44
+ CORS = context.config.proxy["cors"]
45
+ # set cors headers dynamically!
46
+ reverseproxy.add_middleware(
47
+ CORSMiddleware,
48
+ allow_origins=CORS["allowOrigins"],
49
+ allow_credentials=CORS["allowCredentials"],
50
+ allow_methods=CORS["allowMethods"],
51
+ allow_headers=CORS["allowHeaders"],
52
+ )
53
+
54
+ router = ProxyRouter(context=context)
55
+
56
+ client = ProxyClient(http)
57
+ proxy = ReverseProxy(router, client)
58
+
59
+ from fastapi.staticfiles import StaticFiles
60
+ static_dir = build_static_dir(context)
61
+
62
+ print("Mounting static directory:")
63
+ print(" URL: ", f"/{context.config.frontend['lib']['static']}")
64
+ print(" directory:", static_dir)
65
+
66
+ reverseproxy.mount(
67
+ f"/{context.config.frontend["lib"]["static"]}",
68
+ StaticFiles(
69
+ directory=str(static_dir),
70
+ check_dir=True
71
+ ),
72
+ name="static"
73
+ )
74
+
75
+ devtools_uuid = str(uuid4())
76
+
77
+ @reverseproxy.get("/.well-known/appspecific/com.chrome.devtools.json")
78
+ async def chrome_devtools():
79
+ return JSONResponse(
80
+ {
81
+ "workspace": {
82
+ "root": str(context.root),
83
+ "uuid": devtools_uuid,
84
+ },
85
+ }
86
+ )
87
+
88
+ METHODS = context.config.proxy["methods"]
89
+ @reverseproxy.api_route(
90
+ "/{path:path}",
91
+ methods=METHODS,
92
+ summary="http",
93
+ tags=["http"],
94
+ )
95
+ async def http_gateway(request: Request):
96
+ return await proxy.handle_http_request(request=request)
97
+
98
+ return reverseproxy