sveltekit-python-vercel 0.2.0 → 0.4.0
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/README.md
CHANGED
|
@@ -17,13 +17,12 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
17
17
|
- [Fork of `sveltekit-modal`](#fork-of-sveltekit-modal)
|
|
18
18
|
- [Possible future plans](#possible-future-plans)
|
|
19
19
|
|
|
20
|
-
|
|
21
20
|
**This is very much in beta.**
|
|
22
21
|
|
|
23
22
|
## Current Features
|
|
24
23
|
|
|
25
24
|
- Write `+server.py` files nearly the same way you would write `+server.js` files
|
|
26
|
-
- Deploy (
|
|
25
|
+
- Deploy (quasi) automatically to Vercel Serverless
|
|
27
26
|
|
|
28
27
|
## Installing
|
|
29
28
|
|
|
@@ -47,7 +46,7 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
47
46
|
- Update your `svelte.config.js`:
|
|
48
47
|
|
|
49
48
|
```javascript
|
|
50
|
-
import adapter from "@sveltejs/adapter-vercel";
|
|
49
|
+
import adapter from "@sveltejs/adapter-vercel"; // Use the vercel adapter
|
|
51
50
|
import { vitePreprocess } from "@sveltejs/kit/vite";
|
|
52
51
|
|
|
53
52
|
/** @type {import('@sveltejs/kit').Config} */
|
|
@@ -63,8 +62,10 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
63
62
|
```
|
|
64
63
|
|
|
65
64
|
- Update your `vercel.json`
|
|
65
|
+
|
|
66
66
|
- The build command prepares all your endpoints and copies them to the `/api` directory where Vercel looks for functions
|
|
67
67
|
- Functions and Routes tell Vercel how to run and redirect function calls
|
|
68
|
+
|
|
68
69
|
```json
|
|
69
70
|
{
|
|
70
71
|
"buildCommand": "node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs; vite build",
|
|
@@ -85,7 +86,8 @@ Write Python endpoints in [SvelteKit](https://kit.svelte.dev/) and seamlessly de
|
|
|
85
86
|
- Write some `+server.py` endpoints. See the example section below.
|
|
86
87
|
|
|
87
88
|
## Testing Locally
|
|
88
|
-
|
|
89
|
+
|
|
90
|
+
Using [Poetry](https://python-poetry.org/) to manage your virtual environments with this package is recommended.
|
|
89
91
|
|
|
90
92
|
- Run `poetry init` to create a new virtual environment, and follow the steps. Or simply create a `pyproject.toml` like the one below.
|
|
91
93
|
|
|
@@ -99,14 +101,17 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
99
101
|
|
|
100
102
|
[tool.poetry.dependencies]
|
|
101
103
|
python = "^3.9"
|
|
102
|
-
fastapi = "^0.95.
|
|
104
|
+
fastapi = "^0.95.2"
|
|
103
105
|
uvicorn = "^0.22.0"
|
|
104
|
-
|
|
106
|
+
|
|
107
|
+
[tool.poetry.group.dev.dependencies]
|
|
108
|
+
watchfiles = "^0.19.0"
|
|
105
109
|
|
|
106
110
|
[build-system]
|
|
107
111
|
requires = ["poetry-core"]
|
|
108
112
|
build-backend = "poetry.core.masonry.api"
|
|
109
113
|
```
|
|
114
|
+
|
|
110
115
|
- Required packages are python3.9 (that is what Vercel's runtime uses), `fastapi`, and `uvicorn`.
|
|
111
116
|
- Install whatever other dependencies you need from pypi using `poetry add package-name`
|
|
112
117
|
|
|
@@ -115,6 +120,7 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
115
120
|
- You should see both the usual SvelteKit server start as well as the unvicorn server (by default on `http://0.0.0.0:8000`) in the console.
|
|
116
121
|
|
|
117
122
|
## Deploying to Vercel
|
|
123
|
+
|
|
118
124
|
- At the moment this requires a tiny bit of extra labor besides just pushing to your repository. I believe this is because of the way Vercel looks for serverless functions, but I hope to make this a bit easier in the future.
|
|
119
125
|
|
|
120
126
|
- When you make changes to your python endpoints, you have to manually regenerate the `/api` folder by running:
|
|
@@ -122,8 +128,8 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
|
|
|
122
128
|
2. `node ./node_modules/sveltekit-python-vercel/esm/src/vite/sveltekit_python_vercel/bin.mjs`
|
|
123
129
|
- Then commit `requirements.txt` and the changes in `/api` and push.
|
|
124
130
|
|
|
125
|
-
|
|
126
131
|
Note:
|
|
132
|
+
|
|
127
133
|
- To make this a bit smoother, you can add a script to you `package.json`:
|
|
128
134
|
```json
|
|
129
135
|
"scripts": {
|
|
@@ -133,12 +139,10 @@ Note:
|
|
|
133
139
|
```
|
|
134
140
|
- and then just run `pnpm py-update`
|
|
135
141
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
142
|
## Example
|
|
140
143
|
|
|
141
144
|
- Frontend: `/src/routes/py/+page.svelte`
|
|
145
|
+
|
|
142
146
|
```html
|
|
143
147
|
<script lang="ts">
|
|
144
148
|
let a = 0;
|
|
@@ -146,12 +150,12 @@ Note:
|
|
|
146
150
|
let total = 0;
|
|
147
151
|
|
|
148
152
|
async function pyAddPost() {
|
|
149
|
-
const response = await fetch(
|
|
150
|
-
method:
|
|
153
|
+
const response = await fetch("/py", {
|
|
154
|
+
method: "POST",
|
|
151
155
|
body: JSON.stringify({ a, b }),
|
|
152
156
|
headers: {
|
|
153
|
-
|
|
154
|
-
}
|
|
157
|
+
"content-type": "application/json",
|
|
158
|
+
},
|
|
155
159
|
});
|
|
156
160
|
let res = await response.json();
|
|
157
161
|
total = res.sum;
|
|
@@ -159,10 +163,10 @@ Note:
|
|
|
159
163
|
|
|
160
164
|
async function pyAddGet() {
|
|
161
165
|
const response = await fetch(`/py?a=${a}&b=${b}`, {
|
|
162
|
-
method:
|
|
166
|
+
method: "GET",
|
|
163
167
|
headers: {
|
|
164
|
-
|
|
165
|
-
}
|
|
168
|
+
"content-type": "application/json",
|
|
169
|
+
},
|
|
166
170
|
});
|
|
167
171
|
|
|
168
172
|
let res = await response.json();
|
|
@@ -174,9 +178,9 @@ Note:
|
|
|
174
178
|
|
|
175
179
|
<h3>POST Example</h3>
|
|
176
180
|
<form>
|
|
177
|
-
<input type="number" name="a" placeholder="Number 1" bind:value={a} />
|
|
178
|
-
<input type="number" name="b" placeholder="Number 2" bind:value={b} />
|
|
179
|
-
<button on:click|preventDefault={pyAddPost}>Add</button>
|
|
181
|
+
<input type="number" name="a" placeholder="Number 1" bind:value="{a}" />
|
|
182
|
+
<input type="number" name="b" placeholder="Number 2" bind:value="{b}" />
|
|
183
|
+
<button on:click|preventDefault="{pyAddPost}">Add</button>
|
|
180
184
|
</form>
|
|
181
185
|
<h4>Total: {total}</h4>
|
|
182
186
|
|
|
@@ -184,14 +188,15 @@ Note:
|
|
|
184
188
|
|
|
185
189
|
<h3>GET Example</h3>
|
|
186
190
|
<form>
|
|
187
|
-
<input type="number" name="a" placeholder="Number 1" bind:value={a} />
|
|
188
|
-
<input type="number" name="b" placeholder="Number 2" bind:value={b} />
|
|
189
|
-
<button on:click|preventDefault={pyAddGet}>Add</button>
|
|
191
|
+
<input type="number" name="a" placeholder="Number 1" bind:value="{a}" />
|
|
192
|
+
<input type="number" name="b" placeholder="Number 2" bind:value="{b}" />
|
|
193
|
+
<button on:click|preventDefault="{pyAddGet}">Add</button>
|
|
190
194
|
</form>
|
|
191
195
|
<h4>Total: {total}</h4>
|
|
192
196
|
```
|
|
193
197
|
|
|
194
198
|
- Backend: `/src/routes/py/+server.py`
|
|
199
|
+
|
|
195
200
|
```python
|
|
196
201
|
from pydantic import BaseModel
|
|
197
202
|
|
|
@@ -201,18 +206,19 @@ Note:
|
|
|
201
206
|
b: float
|
|
202
207
|
|
|
203
208
|
|
|
204
|
-
async def POST(
|
|
205
|
-
return {"sum":
|
|
209
|
+
async def POST(data: NumberSet):
|
|
210
|
+
return {"sum": data.a + data.b}
|
|
206
211
|
|
|
207
212
|
|
|
208
|
-
async def GET(a, b):
|
|
209
|
-
return {"sum":
|
|
213
|
+
async def GET(a: float, b: float):
|
|
214
|
+
return {"sum": a + b}
|
|
210
215
|
|
|
211
216
|
```
|
|
212
217
|
|
|
213
218
|
### Backend Caveats
|
|
214
219
|
|
|
215
220
|
There are currently a few things that have to be worked around.
|
|
221
|
+
|
|
216
222
|
- `GET` endpoints are directly fed the parameters from the url, so when you define an endpoint
|
|
217
223
|
- All other endpoints are fed the body as a JSON. The recommended way to deal with this is to use a pydantic model and pass it as the singular input to the function.
|
|
218
224
|
|
|
@@ -224,8 +230,9 @@ Check out the awesome [sveltekit-modal](https://github.com/semicognitive/sveltek
|
|
|
224
230
|
|
|
225
231
|
## Possible future plans
|
|
226
232
|
|
|
233
|
+
- [X] Add hot reloading in dev mode
|
|
227
234
|
- [ ] Generate endpoints (/api folder) automatically during build
|
|
228
235
|
- [ ] Auto create requirements.txt from pyproject.toml (both related to vercel functions being checked/handled before build)
|
|
229
236
|
- [ ] Add form actions
|
|
230
237
|
- [ ] Add load functions
|
|
231
|
-
- [ ] Add helper functions to automatically call API endpoints in project
|
|
238
|
+
- [ ] Add helper functions to automatically call API endpoints in project\
|
package/esm/src/vite/mod.js
CHANGED
|
@@ -14,10 +14,9 @@ const get_pyServerEndpointAsString = (app_url, serve = false) => `
|
|
|
14
14
|
fullURL = new URL('/api' + url.pathname, new URL('${app_url}')) + url.search;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
console.log(\`Reached python endpoint of \${method} \${fullURL}\`)
|
|
17
|
+
console.log(\`PY: Reached python endpoint of \${method} \${fullURL}\`)
|
|
18
18
|
let requestBody = await request.clone().text();
|
|
19
|
-
console.log(\`Body: \${requestBody}\`);
|
|
20
|
-
console.log(\`Content-Type: \${request.headers.get('content-type')}\`);
|
|
19
|
+
console.log(\`PY: Body: \${requestBody}\`);
|
|
21
20
|
|
|
22
21
|
if (method === 'GET') {
|
|
23
22
|
requestBody = null;
|
|
@@ -79,11 +78,11 @@ export async function sveltekit_python_vercel(opts = {}) {
|
|
|
79
78
|
name: "vite-plugin-sveltekit_python-build",
|
|
80
79
|
apply: "build",
|
|
81
80
|
async configResolved(config) {
|
|
82
|
-
console.log("BUILD DEBUG");
|
|
83
|
-
console.log("ROOT PATH: " + config.root);
|
|
84
|
-
console.log("LOADED VERCEL URL: " + loadEnv("", config.root, "").VERCEL_URL);
|
|
81
|
+
console.log("PY: BUILD DEBUG");
|
|
82
|
+
console.log("PY: ROOT PATH: " + config.root);
|
|
83
|
+
console.log("PY: LOADED VERCEL URL: " + loadEnv("", config.root, "").VERCEL_URL);
|
|
85
84
|
const packagelocation = path.join(config.root, "node_modules", "sveltekit-python-vercel", "esm/src/vite");
|
|
86
|
-
console.log("PACKAGE LOCATION: " + packagelocation);
|
|
85
|
+
console.log("PY: PACKAGE LOCATION: " + packagelocation);
|
|
87
86
|
const python_path = opts.python_path ?? (await which("python3"));
|
|
88
87
|
await run$ `cd ${packagelocation}`;
|
|
89
88
|
await run$ `${python_path} ${packagelocation}/sveltekit_python_vercel/build.py --root ${config.root}`;
|
|
@@ -95,7 +94,7 @@ export async function sveltekit_python_vercel(opts = {}) {
|
|
|
95
94
|
const api_url = path.join(httpPrefix + loadEnv("", config.root, "").VERCEL_URL);
|
|
96
95
|
// get current Vercel deploy URL
|
|
97
96
|
sveltekit_url = new URL(api_url);
|
|
98
|
-
console.log("Build API URL: " + sveltekit_url.toString());
|
|
97
|
+
console.log("PY: Build API URL: " + sveltekit_url.toString());
|
|
99
98
|
},
|
|
100
99
|
};
|
|
101
100
|
const plugin_py_server_endpoint_serve = {
|
|
@@ -25,7 +25,8 @@ for module_path in glob.glob(str(root_dir / 'src/routes/**/+server.py'), recursi
|
|
|
25
25
|
|
|
26
26
|
# replace the root_dir with api_dir
|
|
27
27
|
api_route = api_dir / Path(module_path).absolute().relative_to(root_dir / "src/routes")
|
|
28
|
-
|
|
28
|
+
api_route = Path(str(api_route).replace('[', '{').replace(']', '}'))
|
|
29
|
+
|
|
29
30
|
if not api_route.parent.exists():
|
|
30
31
|
api_route.parent.mkdir(parents=True)
|
|
31
32
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import glob
|
|
3
2
|
import importlib
|
|
4
3
|
import importlib.util
|
|
4
|
+
import os
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from fastapi import FastAPI, Request
|
|
@@ -22,29 +22,27 @@ for module_path in glob.glob('./**/+server.py', recursive=True):
|
|
|
22
22
|
|
|
23
23
|
api_route = module_path[1:] if module_path.startswith('./') else module_path
|
|
24
24
|
api_route = str(Path(api_route).parent)
|
|
25
|
+
|
|
26
|
+
# Replace square brackets with curly brackets
|
|
27
|
+
api_route = api_route.replace('[', '{').replace(']', '}')
|
|
25
28
|
|
|
26
29
|
mod = importlib.import_module(module_name, module_package)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if hasattr(mod, 'DELETE'):
|
|
45
|
-
app.add_api_route(api_route, mod.DELETE, methods=["DELETE"])
|
|
46
|
-
print(f"PYTHON ENDPOINT: Added {module_path} [DELETE] at {api_route}")
|
|
47
|
-
|
|
30
|
+
|
|
31
|
+
# Add endpoints
|
|
32
|
+
for method in ["GET", "POST", "PATCH", "PUT", "DELETE"]:
|
|
33
|
+
|
|
34
|
+
# Check for duplicate methods
|
|
35
|
+
if hasattr(mod, method) and hasattr(mod, method.lower()):
|
|
36
|
+
raise Exception(
|
|
37
|
+
f"Duplicate method {method} and {method.lower()} in {api_route}"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
elif hasattr(mod, method):
|
|
41
|
+
app.add_api_route(api_route, getattr(mod, method), methods=[method])
|
|
42
|
+
print(f"PYTHON ENDPOINT: Added {module_path} [{method}] at {api_route}")
|
|
43
|
+
elif hasattr(mod, method.lower()):
|
|
44
|
+
app.add_api_route(api_route, getattr(mod, method.lower()), methods=[method])
|
|
45
|
+
print(f"PYTHON ENDPOINT: Added {module_path} [{method}] at {api_route}")
|
|
48
46
|
|
|
49
47
|
@app.exception_handler(Exception)
|
|
50
48
|
async def unicorn_exception_handler(request: Request, exc: Exception):
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import uvicorn
|
|
2
1
|
import argparse
|
|
3
|
-
import
|
|
2
|
+
import glob
|
|
4
3
|
import importlib
|
|
5
4
|
import importlib.util
|
|
6
|
-
import glob
|
|
7
5
|
import shutil
|
|
8
6
|
from pathlib import Path
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
from fastapi
|
|
8
|
+
import uvicorn
|
|
9
|
+
from fastapi import FastAPI
|
|
12
10
|
|
|
13
11
|
parser = argparse.ArgumentParser(description="Run Sveltekit Python Server")
|
|
14
12
|
parser.add_argument("--host", default="0.0.0.0", help="Server hostname")
|
|
@@ -18,59 +16,64 @@ args = parser.parse_args()
|
|
|
18
16
|
|
|
19
17
|
app = FastAPI()
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
root_dir = Path(args.root).absolute()
|
|
20
|
+
|
|
21
|
+
api_dir = Path("./sveltekit_python_vercel").absolute()
|
|
22
|
+
|
|
23
|
+
route_dir = root_dir.joinpath("src/routes")
|
|
24
|
+
|
|
25
|
+
watch_modules = [] # list of modules to watch for changes
|
|
26
|
+
|
|
27
|
+
for module_path in glob.glob(
|
|
28
|
+
route_dir.joinpath("**/+server.py").as_posix(), recursive=True
|
|
29
|
+
):
|
|
30
|
+
abs_module_path = Path(module_path).absolute()
|
|
31
|
+
|
|
32
|
+
watch_modules.append(abs_module_path.parent.as_posix())
|
|
33
|
+
|
|
34
|
+
api_route = api_dir.joinpath(abs_module_path.relative_to(root_dir / "src/routes"))
|
|
35
|
+
|
|
36
|
+
if not api_route.parent.exists():
|
|
37
|
+
api_route.parent.mkdir(parents=True)
|
|
38
|
+
|
|
39
|
+
# copy module path to api_route
|
|
40
|
+
shutil.copy(module_path, api_route.parent)
|
|
41
|
+
|
|
42
|
+
module_name = api_route.stem
|
|
43
|
+
|
|
44
|
+
spec = importlib.util.spec_from_file_location(module_name, api_route)
|
|
45
|
+
mod = importlib.util.module_from_spec(spec)
|
|
46
|
+
spec.loader.exec_module(mod)
|
|
47
|
+
|
|
48
|
+
# Get the relative path of the module from the API directory
|
|
49
|
+
rel_path = api_route.relative_to(api_dir)
|
|
50
|
+
|
|
51
|
+
# Convert the relative path to a string and remove the file extension
|
|
52
|
+
api_path = f"/{rel_path.parent}"
|
|
53
|
+
|
|
54
|
+
# Replace square brackets with curly brackets
|
|
55
|
+
api_path = api_path.replace("[", "{").replace("]", "}")
|
|
56
|
+
|
|
57
|
+
# Add endpoints
|
|
58
|
+
for method in ["GET", "POST", "PATCH", "PUT", "DELETE"]:
|
|
59
|
+
# Check for duplicate methods
|
|
60
|
+
if hasattr(mod, method) and hasattr(mod, method.lower()):
|
|
61
|
+
raise Exception(
|
|
62
|
+
f"Duplicate method {method} and {method.lower()} in {api_route}"
|
|
63
|
+
)
|
|
64
|
+
elif hasattr(mod, method):
|
|
65
|
+
app.add_api_route(api_path, getattr(mod, method), methods=[method])
|
|
66
|
+
elif hasattr(mod, method.lower()):
|
|
67
|
+
app.add_api_route(api_path, getattr(mod, method.lower()), methods=[method])
|
|
68
|
+
|
|
23
69
|
|
|
24
70
|
if __name__ == "__main__":
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if not api_route.parent.exists():
|
|
36
|
-
api_route.parent.mkdir(parents=True)
|
|
37
|
-
|
|
38
|
-
# copy module path to api_route
|
|
39
|
-
shutil.copy(module_path, api_route.parent)
|
|
40
|
-
print(f"PYTHON ENDPOINT: Copied {module_path} to {api_route.parent}")
|
|
41
|
-
|
|
42
|
-
# Get the module name from the module path
|
|
43
|
-
module_name = api_route.stem
|
|
44
|
-
|
|
45
|
-
# Import the module dynamically
|
|
46
|
-
spec = importlib.util.spec_from_file_location(module_name, api_route)
|
|
47
|
-
mod = importlib.util.module_from_spec(spec)
|
|
48
|
-
spec.loader.exec_module(mod)
|
|
49
|
-
|
|
50
|
-
# Get the relative path of the module from the API directory
|
|
51
|
-
rel_path = api_route.relative_to(api_dir)
|
|
52
|
-
# Convert the relative path to a string and remove the file extension
|
|
53
|
-
api_path = "/" + str(rel_path.parent)
|
|
54
|
-
|
|
55
|
-
print("ADDING API PATH:", rel_path, api_path)
|
|
56
|
-
|
|
57
|
-
if hasattr(mod, 'GET'):
|
|
58
|
-
app.add_api_route(api_path, mod.GET, methods=["GET"])
|
|
59
|
-
|
|
60
|
-
if hasattr(mod, 'POST'):
|
|
61
|
-
app.add_api_route(api_path, mod.POST, methods=["POST"])
|
|
62
|
-
|
|
63
|
-
if hasattr(mod, 'PATCH'):
|
|
64
|
-
app.add_api_route(api_path, mod.PATCH, methods=["PATCH"])
|
|
65
|
-
|
|
66
|
-
if hasattr(mod, 'PUT'):
|
|
67
|
-
app.add_api_route(api_path, mod.PUT, methods=["PUT"])
|
|
68
|
-
|
|
69
|
-
if hasattr(mod, 'DELETE'):
|
|
70
|
-
app.add_api_route(api_path, mod.DELETE, methods=["DELETE"])
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
config = uvicorn.Config(app_factory, host=args.host, port=args.port, log_level="info", factory=True)
|
|
74
|
-
server = uvicorn.Server(config)
|
|
75
|
-
print(f"Hosting on http://{args.host}:{args.port}")
|
|
76
|
-
server.run()
|
|
71
|
+
uvicorn.run(
|
|
72
|
+
"sveltekit_python_vercel.serve:app",
|
|
73
|
+
host=args.host,
|
|
74
|
+
port=args.port,
|
|
75
|
+
log_level="info",
|
|
76
|
+
reload=True,
|
|
77
|
+
reload_includes=[*set(watch_modules)],
|
|
78
|
+
reload_excludes=[api_dir.as_posix()],
|
|
79
|
+
)
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"module": "./esm/mod.js",
|
|
3
3
|
"types": "./types/mod.d.ts",
|
|
4
4
|
"name": "sveltekit-python-vercel",
|
|
5
|
-
"version": "v0.
|
|
5
|
+
"version": "v0.4.0",
|
|
6
6
|
"description": "Write Sveltekit server endpoints in Python and seamlessly deploy to Vercel",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|