@vercel/python 6.14.1 → 6.15.1
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.
- package/dist/index.js +499 -383
- package/package.json +5 -4
- package/vc_init_dev_asgi.py +82 -4
- package/vc_init_dev_wsgi.py +60 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/python",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.15.1",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"directory": "packages/python"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@vercel/python-analysis": "0.
|
|
19
|
+
"@vercel/python-analysis": "0.6.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@renovatebot/pep440": "4.2.1",
|
|
@@ -34,8 +34,9 @@
|
|
|
34
34
|
"smol-toml": "1.5.2",
|
|
35
35
|
"vitest": "2.1.4",
|
|
36
36
|
"which": "3.0.0",
|
|
37
|
-
"@vercel/build-utils": "13.4.
|
|
38
|
-
"@vercel/error-utils": "2.0.3"
|
|
37
|
+
"@vercel/build-utils": "13.4.3",
|
|
38
|
+
"@vercel/error-utils": "2.0.3",
|
|
39
|
+
"@vercel/python-runtime": "0.5.1"
|
|
39
40
|
},
|
|
40
41
|
"scripts": {
|
|
41
42
|
"build": "node ../../utils/build-builder.mjs",
|
package/vc_init_dev_asgi.py
CHANGED
|
@@ -45,6 +45,82 @@ USER_ASGI_APP = _CAND if callable(_CAND) else _app
|
|
|
45
45
|
|
|
46
46
|
PUBLIC_DIR = 'public'
|
|
47
47
|
|
|
48
|
+
|
|
49
|
+
def _normalize_service_route_prefix(raw_prefix):
|
|
50
|
+
if not raw_prefix:
|
|
51
|
+
return ''
|
|
52
|
+
|
|
53
|
+
prefix = raw_prefix.strip()
|
|
54
|
+
if not prefix:
|
|
55
|
+
return ''
|
|
56
|
+
|
|
57
|
+
if not prefix.startswith('/'):
|
|
58
|
+
prefix = f'/{prefix}'
|
|
59
|
+
|
|
60
|
+
return '' if prefix == '/' else prefix.rstrip('/')
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _is_service_route_prefix_strip_enabled():
|
|
64
|
+
raw = os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX_STRIP')
|
|
65
|
+
if not raw:
|
|
66
|
+
return False
|
|
67
|
+
return raw.lower() in ('1', 'true')
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
_SERVICE_ROUTE_PREFIX = (
|
|
71
|
+
_normalize_service_route_prefix(os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX'))
|
|
72
|
+
if _is_service_route_prefix_strip_enabled()
|
|
73
|
+
else ''
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _strip_service_route_prefix(path_value):
|
|
78
|
+
if not path_value:
|
|
79
|
+
path_value = '/'
|
|
80
|
+
elif not path_value.startswith('/'):
|
|
81
|
+
path_value = f'/{path_value}'
|
|
82
|
+
|
|
83
|
+
prefix = _SERVICE_ROUTE_PREFIX
|
|
84
|
+
if not prefix:
|
|
85
|
+
return path_value, ''
|
|
86
|
+
|
|
87
|
+
if path_value == prefix:
|
|
88
|
+
return '/', prefix
|
|
89
|
+
|
|
90
|
+
if path_value.startswith(f'{prefix}/'):
|
|
91
|
+
stripped = path_value[len(prefix):]
|
|
92
|
+
return stripped if stripped else '/', prefix
|
|
93
|
+
|
|
94
|
+
return path_value, ''
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _apply_service_route_prefix_to_scope(scope):
|
|
98
|
+
path_value, matched_prefix = _strip_service_route_prefix(scope.get('path', '/'))
|
|
99
|
+
if not matched_prefix:
|
|
100
|
+
return scope
|
|
101
|
+
|
|
102
|
+
updated_scope = dict(scope)
|
|
103
|
+
updated_scope['path'] = path_value
|
|
104
|
+
|
|
105
|
+
raw_path = scope.get('raw_path')
|
|
106
|
+
if isinstance(raw_path, (bytes, bytearray)):
|
|
107
|
+
try:
|
|
108
|
+
decoded = bytes(raw_path).decode('utf-8', 'surrogateescape')
|
|
109
|
+
stripped_raw, _ = _strip_service_route_prefix(decoded)
|
|
110
|
+
updated_scope['raw_path'] = stripped_raw.encode(
|
|
111
|
+
'utf-8', 'surrogateescape'
|
|
112
|
+
)
|
|
113
|
+
except Exception:
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
existing_root = scope.get('root_path', '') or ''
|
|
117
|
+
if existing_root and existing_root != '/':
|
|
118
|
+
existing_root = existing_root.rstrip('/')
|
|
119
|
+
else:
|
|
120
|
+
existing_root = ''
|
|
121
|
+
updated_scope['root_path'] = f'{existing_root}{matched_prefix}'
|
|
122
|
+
return updated_scope
|
|
123
|
+
|
|
48
124
|
# Prepare static files app (if starlette/fastapi installed)
|
|
49
125
|
static_app = None
|
|
50
126
|
if StaticFiles is not None:
|
|
@@ -59,19 +135,21 @@ if StaticFiles is not None:
|
|
|
59
135
|
|
|
60
136
|
|
|
61
137
|
async def app(scope, receive, send):
|
|
62
|
-
|
|
63
|
-
|
|
138
|
+
effective_scope = _apply_service_route_prefix_to_scope(scope)
|
|
139
|
+
|
|
140
|
+
if static_app is not None and effective_scope.get('type') == 'http':
|
|
141
|
+
req_path = effective_scope.get('path', '/') or '/'
|
|
64
142
|
safe = _p.normpath(req_path).lstrip('/')
|
|
65
143
|
full = _p.join(PUBLIC_DIR, safe)
|
|
66
144
|
try:
|
|
67
145
|
base = _p.realpath(PUBLIC_DIR)
|
|
68
146
|
target = _p.realpath(full)
|
|
69
147
|
if (target == base or target.startswith(base + _p.sep)) and _p.isfile(target):
|
|
70
|
-
await static_app(
|
|
148
|
+
await static_app(effective_scope, receive, send)
|
|
71
149
|
return
|
|
72
150
|
except Exception:
|
|
73
151
|
pass
|
|
74
|
-
await USER_ASGI_APP(
|
|
152
|
+
await USER_ASGI_APP(effective_scope, receive, send)
|
|
75
153
|
|
|
76
154
|
|
|
77
155
|
if __name__ == '__main__':
|
package/vc_init_dev_wsgi.py
CHANGED
|
@@ -24,6 +24,54 @@ def _color(text: str, code: str) -> str:
|
|
|
24
24
|
USER_MODULE = "__VC_DEV_MODULE_PATH__"
|
|
25
25
|
PUBLIC_DIR = "public"
|
|
26
26
|
|
|
27
|
+
|
|
28
|
+
def _normalize_service_route_prefix(raw_prefix):
|
|
29
|
+
if not raw_prefix:
|
|
30
|
+
return ''
|
|
31
|
+
|
|
32
|
+
prefix = raw_prefix.strip()
|
|
33
|
+
if not prefix:
|
|
34
|
+
return ''
|
|
35
|
+
|
|
36
|
+
if not prefix.startswith('/'):
|
|
37
|
+
prefix = f'/{prefix}'
|
|
38
|
+
|
|
39
|
+
return '' if prefix == '/' else prefix.rstrip('/')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _is_service_route_prefix_strip_enabled():
|
|
43
|
+
raw = os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX_STRIP')
|
|
44
|
+
if not raw:
|
|
45
|
+
return False
|
|
46
|
+
return raw.lower() in ('1', 'true')
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
_SERVICE_ROUTE_PREFIX = (
|
|
50
|
+
_normalize_service_route_prefix(os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX'))
|
|
51
|
+
if _is_service_route_prefix_strip_enabled()
|
|
52
|
+
else ''
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _strip_service_route_prefix(path_info):
|
|
57
|
+
if not path_info:
|
|
58
|
+
path_info = '/'
|
|
59
|
+
elif not path_info.startswith('/'):
|
|
60
|
+
path_info = f'/{path_info}'
|
|
61
|
+
|
|
62
|
+
prefix = _SERVICE_ROUTE_PREFIX
|
|
63
|
+
if not prefix:
|
|
64
|
+
return path_info, ''
|
|
65
|
+
|
|
66
|
+
if path_info == prefix:
|
|
67
|
+
return '/', prefix
|
|
68
|
+
|
|
69
|
+
if path_info.startswith(f'{prefix}/'):
|
|
70
|
+
stripped = path_info[len(prefix):]
|
|
71
|
+
return stripped if stripped else '/', prefix
|
|
72
|
+
|
|
73
|
+
return path_info, ''
|
|
74
|
+
|
|
27
75
|
_mod = import_module(USER_MODULE)
|
|
28
76
|
_app = getattr(_mod, "app", None)
|
|
29
77
|
if _app is None:
|
|
@@ -74,6 +122,18 @@ def _not_found(start_response):
|
|
|
74
122
|
|
|
75
123
|
|
|
76
124
|
def _combined_app(environ, start_response):
|
|
125
|
+
path_info, matched_prefix = _strip_service_route_prefix(
|
|
126
|
+
environ.get("PATH_INFO", "/") or "/"
|
|
127
|
+
)
|
|
128
|
+
environ["PATH_INFO"] = path_info
|
|
129
|
+
if matched_prefix:
|
|
130
|
+
script_name = environ.get("SCRIPT_NAME", "") or ""
|
|
131
|
+
if script_name and script_name != "/":
|
|
132
|
+
script_name = script_name.rstrip("/")
|
|
133
|
+
else:
|
|
134
|
+
script_name = ""
|
|
135
|
+
environ["SCRIPT_NAME"] = f"{script_name}{matched_prefix}"
|
|
136
|
+
|
|
77
137
|
# Try static first; if 404 then delegate to user app
|
|
78
138
|
captured_status = ""
|
|
79
139
|
captured_headers = tuple()
|