create-caspian-app 0.2.0-beta.9 → 0.2.0-beta.90
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 +232 -232
- package/dist/.github/copilot-instructions.md +157 -0
- package/dist/.python-version +1 -0
- package/dist/.vscode/settings.json +4 -0
- package/dist/AGENTS.md +118 -0
- package/dist/CLAUDE.md +1 -0
- package/dist/app-gitignore +5 -1
- package/dist/caspian.js +1 -1
- package/dist/index.js +1 -1
- package/dist/main.py +120 -34
- package/dist/postcss.config.js +4 -2
- package/dist/public/js/main.js +13 -1
- package/dist/public/js/pp-reactive-v2.js +1 -1
- package/dist/pyproject.toml +1 -1
- package/dist/settings/bs-config.json +6 -6
- package/dist/settings/bs-config.ts +132 -19
- package/dist/settings/files-list.ts +11 -3
- package/dist/settings/project-name.ts +48 -45
- package/dist/settings/python-server.ts +22 -7
- package/dist/settings/restart-mcp.ts +229 -0
- package/dist/settings/run-postcss.ts +317 -0
- package/dist/settings/run-vite-watch.ts +37 -0
- package/dist/settings/utils.ts +30 -8
- package/dist/src/app/error.html +66 -85
- package/dist/src/app/globals.css +3 -1
- package/dist/src/app/layout.html +0 -1
- package/dist/src/lib/auth/auth_config.py +10 -1
- package/dist/src/lib/mcp/fastmcp.json +15 -0
- package/dist/src/lib/mcp/mcp_server.py +91 -0
- package/dist/ts/main.ts +20 -1
- package/dist/ts/tailwind-merge.ts +13 -0
- package/package.json +4 -4
- package/dist/settings/build.ts +0 -19
- package/dist/settings/component-map.json +0 -1
- package/dist/settings/files-list.json +0 -1
package/README.md
CHANGED
|
@@ -1,70 +1,114 @@
|
|
|
1
1
|
# Caspian — The Native Python Web Framework for the Reactive Web
|
|
2
2
|
|
|
3
|
-
Caspian is a high
|
|
3
|
+
Caspian is a high-performance, FastAPI-powered full-stack framework that brings reactive UI to Python without forcing a JavaScript backend. It combines:
|
|
4
4
|
|
|
5
5
|
- **FastAPI Engine** for async-native performance and the broader FastAPI ecosystem
|
|
6
|
-
-
|
|
7
|
-
- **Direct async RPC** (
|
|
8
|
-
- **File
|
|
6
|
+
- **Hybrid Frontend Engine**: start with zero-build HTML, then upgrade to Vite + NPM + TypeScript when needed
|
|
7
|
+
- **Direct async RPC** ("Zero-API"): call Python functions from the browser via `pp.rpc()`
|
|
8
|
+
- **File-system routing** with nested layouts and dynamic routes (Next.js App Router mental model)
|
|
9
9
|
- **Prisma ORM integration** with an auto-generated, type-safe Python client
|
|
10
|
-
-
|
|
10
|
+
- **PulsePoint** — a lightweight browser-side reactive runtime for interactive UI
|
|
11
|
+
- **Session-based authentication** with RBAC support and built-in security defaults
|
|
11
12
|
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
## Quick Start
|
|
15
16
|
|
|
16
|
-
###
|
|
17
|
+
### Requirements
|
|
17
18
|
|
|
18
|
-
- **Node.js**:
|
|
19
|
+
- **Node.js**: v24.13.1+
|
|
19
20
|
- **Python**: v3.14.0+
|
|
20
21
|
|
|
21
|
-
###
|
|
22
|
+
### Create an app (interactive wizard)
|
|
22
23
|
|
|
23
24
|
```bash
|
|
24
25
|
npx create-caspian-app@latest
|
|
25
26
|
```
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
The wizard walks through the main project options:
|
|
28
29
|
|
|
29
30
|
- Project name
|
|
30
|
-
- Tailwind CSS
|
|
31
|
-
-
|
|
32
|
-
- Backend only (no frontend assets)
|
|
33
|
-
- TypeScript support
|
|
31
|
+
- Feature toggles: backend-only mode, Tailwind CSS, Prisma, MCP, TypeScript
|
|
32
|
+
- Starter kit selection (basic, fullstack, api, realtime)
|
|
34
33
|
|
|
35
|
-
###
|
|
34
|
+
### Run dev server
|
|
36
35
|
|
|
37
36
|
```bash
|
|
38
37
|
cd my-app
|
|
39
38
|
npm run dev
|
|
40
39
|
```
|
|
41
40
|
|
|
41
|
+
> **Note:** Many Caspian projects use BrowserSync plus PostCSS watchers rather than a Vite dev server. Check `package.json` for the actual dev script.
|
|
42
|
+
|
|
42
43
|
---
|
|
43
44
|
|
|
44
|
-
## What
|
|
45
|
+
## What "Reactive Python" looks like
|
|
46
|
+
|
|
47
|
+
A Caspian page is plain HTML with reactive directives plus a small `<script>` block for state. The framework handles the rest.
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
### Route template (`src/app/todos/index.html`)
|
|
47
50
|
|
|
48
51
|
```html
|
|
49
|
-
<!--
|
|
52
|
+
<!-- @import { Badge } from "../components/ui" -->
|
|
53
|
+
|
|
54
|
+
<section>
|
|
55
|
+
<div class="flex gap-2 mb-4">
|
|
56
|
+
<x-badge variant="default">Tasks: {todos.length}</x-badge>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<ul>
|
|
60
|
+
<template pp-for="(todo, index) in todos">
|
|
61
|
+
<li key="{todo.id}" class="p-2 border-b">
|
|
62
|
+
{index + 1}. {todo.title}
|
|
63
|
+
<button onclick="removeTodo(todo.id)">Remove</button>
|
|
64
|
+
</li>
|
|
65
|
+
</template>
|
|
66
|
+
</ul>
|
|
67
|
+
|
|
68
|
+
<script>
|
|
69
|
+
const [todos, setTodos] = pp.state([]);
|
|
70
|
+
function removeTodo(id) {
|
|
71
|
+
setTodos(todos.filter((todo) => todo.id !== id));
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
74
|
+
</section>
|
|
75
|
+
```
|
|
50
76
|
|
|
51
|
-
|
|
52
|
-
<!-- @import { Badge } from ../components/ui -->
|
|
77
|
+
### Backend RPC (`src/app/todos/index.py`)
|
|
53
78
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
```python
|
|
80
|
+
from casp.rpc import rpc
|
|
81
|
+
from casp.validate import Validate
|
|
82
|
+
from src.lib.prisma.db import prisma
|
|
83
|
+
|
|
84
|
+
@rpc()
|
|
85
|
+
async def create_todo(title):
|
|
86
|
+
if Validate.with_rules(title, "required|min:3") is not True:
|
|
87
|
+
raise ValueError("Title must be at least 3 chars")
|
|
88
|
+
|
|
89
|
+
new_todo = await prisma.todo.create(data={
|
|
90
|
+
"title": title,
|
|
91
|
+
"completed": False
|
|
92
|
+
})
|
|
93
|
+
return new_todo.to_dict()
|
|
57
94
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
95
|
+
@rpc(require_auth=True)
|
|
96
|
+
async def delete_todo(id, _current_user_id=None):
|
|
97
|
+
await prisma.todo.delete(where={"id": id})
|
|
98
|
+
return {"success": True}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Frontend call
|
|
64
102
|
|
|
103
|
+
```html
|
|
65
104
|
<script>
|
|
66
|
-
|
|
67
|
-
|
|
105
|
+
async function add(e) {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
const data = Object.fromEntries(new FormData(e.target));
|
|
108
|
+
const newTodo = await pp.rpc("create_todo", data);
|
|
109
|
+
setTodos([newTodo, ...todos]);
|
|
110
|
+
e.target.reset();
|
|
111
|
+
}
|
|
68
112
|
</script>
|
|
69
113
|
```
|
|
70
114
|
|
|
@@ -74,37 +118,31 @@ A Caspian page can be plain HTML with reactive directives, plus a small `<script
|
|
|
74
118
|
|
|
75
119
|
### FastAPI engine, async-native
|
|
76
120
|
|
|
77
|
-
Your logic runs in native async Python and can leverage FastAPI/Starlette features (
|
|
121
|
+
Your logic runs in native async Python and can leverage FastAPI/Starlette features (dependency injection, middleware, validation, etc.) without a separate JS backend.
|
|
78
122
|
|
|
79
123
|
### Hybrid frontend engine (zero-build → Vite)
|
|
80
124
|
|
|
81
125
|
Start with simple HTML-first development for speed and clarity, then adopt Vite + NPM + TypeScript when you need richer libraries or complex bundles.
|
|
82
126
|
|
|
83
|
-
###
|
|
127
|
+
### "Zero-API" server actions (RPC)
|
|
84
128
|
|
|
85
|
-
Define `async def` actions and call them directly from the browser; Caspian handles serialization, security, and async execution.
|
|
129
|
+
Define `async def` actions decorated with `@rpc()` and call them directly from the browser; Caspian handles serialization, security, and async execution via `pp.rpc()`.
|
|
86
130
|
|
|
87
|
-
### File
|
|
131
|
+
### File-system routing with nested layouts
|
|
88
132
|
|
|
89
133
|
Routes are determined by files in `src/app`, supporting dynamic segments (`[id]`), catch-alls (`[...slug]`), route groups (`(auth)`), and layout nesting via `layout.html`.
|
|
90
134
|
|
|
91
135
|
### Prisma ORM integration (type-safe Python client)
|
|
92
136
|
|
|
93
|
-
Define a single Prisma schema and generate a typed Python client—autocomplete-first database access without boilerplate.
|
|
137
|
+
Define a single Prisma schema and generate a typed Python client — autocomplete-first database access without boilerplate.
|
|
94
138
|
|
|
95
|
-
###
|
|
139
|
+
### PulsePoint reactive runtime
|
|
96
140
|
|
|
97
|
-
|
|
141
|
+
A lightweight browser-side reactive runtime ships with Caspian. It follows a React-like mental model but is HTML-first rather than JSX-first, with `pp.state`, `pp.effect`, `pp.ref`, `pp-context`, `pp-for`, and `pp.portal`.
|
|
98
142
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
## Installation & DX setup (VS Code)
|
|
102
|
-
|
|
103
|
-
For the best developer experience, Caspian’s docs recommend:
|
|
143
|
+
### Security defaults and authentication
|
|
104
144
|
|
|
105
|
-
-
|
|
106
|
-
- **Prisma** schema formatting/highlighting
|
|
107
|
-
- **Tailwind CSS** IntelliSense & class sorting
|
|
145
|
+
Built-in CSRF protection, strict Origin validation, HttpOnly cookies, and a session-based auth model with OAuth provider support.
|
|
108
146
|
|
|
109
147
|
---
|
|
110
148
|
|
|
@@ -112,31 +150,31 @@ For the best developer experience, Caspian’s docs recommend:
|
|
|
112
150
|
|
|
113
151
|
### Routing
|
|
114
152
|
|
|
115
|
-
Caspian
|
|
153
|
+
Caspian follows the same mental model as the Next.js App Router. Your directory structure becomes your URL structure.
|
|
116
154
|
|
|
117
|
-
| File
|
|
155
|
+
| File | URL |
|
|
118
156
|
| ------------------------------- | ------------- |
|
|
119
157
|
| `src/app/index.html` | `/` |
|
|
120
|
-
| `src/app/about/index.
|
|
158
|
+
| `src/app/about/index.html` | `/about` |
|
|
121
159
|
| `src/app/blog/posts/index.html` | `/blog/posts` |
|
|
122
160
|
|
|
123
161
|
#### Dynamic segments
|
|
124
162
|
|
|
125
|
-
```
|
|
126
|
-
src/app/users/[id]/index.
|
|
163
|
+
```
|
|
164
|
+
src/app/users/[id]/index.html -> /users/123
|
|
127
165
|
```
|
|
128
166
|
|
|
129
167
|
#### Catch-all segments
|
|
130
168
|
|
|
131
|
-
```
|
|
132
|
-
src/app/docs/[...slug]/index.
|
|
169
|
+
```
|
|
170
|
+
src/app/docs/[...slug]/index.html -> /docs/getting-started/setup
|
|
133
171
|
```
|
|
134
172
|
|
|
135
173
|
#### Route groups (organize without changing URLs)
|
|
136
174
|
|
|
137
|
-
```
|
|
138
|
-
src/app/(auth)/login/index.
|
|
139
|
-
src/app/(auth)/register/index.
|
|
175
|
+
```
|
|
176
|
+
src/app/(auth)/login/index.html -> /login
|
|
177
|
+
src/app/(auth)/register/index.html -> /register
|
|
140
178
|
```
|
|
141
179
|
|
|
142
180
|
#### Nested layouts
|
|
@@ -144,241 +182,205 @@ src/app/(auth)/register/index.py -> /register
|
|
|
144
182
|
Layouts wrap pages and preserve state during navigation:
|
|
145
183
|
|
|
146
184
|
- Root: `src/app/layout.html`
|
|
147
|
-
-
|
|
185
|
+
- Section: e.g., `/dashboard/settings` inherits root + dashboard layout automatically
|
|
186
|
+
|
|
187
|
+
> **Rule:** For UI routes, keep markup in `index.html` and server logic in `index.py`. For section layouts, keep the visible wrapper in `layout.html` and layout-level props in `layout.py`.
|
|
148
188
|
|
|
149
189
|
---
|
|
150
190
|
|
|
151
191
|
### Components (Python-first, HTML when you want it)
|
|
152
192
|
|
|
153
|
-
Components are Python functions decorated with `@component`.
|
|
193
|
+
Components are Python functions decorated with `@component`. Import them with `<!-- @import ... -->` comments and render them with `x-*` tags.
|
|
154
194
|
|
|
155
|
-
#### Atomic component
|
|
195
|
+
#### Atomic component
|
|
156
196
|
|
|
157
|
-
```
|
|
158
|
-
from casp.html_attrs import get_attributes, merge_classes
|
|
197
|
+
```python
|
|
159
198
|
from casp.component_decorator import component
|
|
199
|
+
from casp.html_attrs import get_attributes, merge_classes
|
|
160
200
|
|
|
161
201
|
@component
|
|
162
|
-
def Container(**props):
|
|
202
|
+
def Container(children: str = "", **props) -> str:
|
|
163
203
|
incoming_class = props.pop("class", "")
|
|
164
204
|
final_class = merge_classes("mx-auto max-w-7xl px-4", incoming_class)
|
|
165
|
-
|
|
166
|
-
children = props.pop("children", "")
|
|
167
|
-
|
|
168
205
|
attributes = get_attributes({"class": final_class}, props)
|
|
169
206
|
return f'<div {attributes}>{children}</div>'
|
|
170
207
|
```
|
|
171
208
|
|
|
172
|
-
|
|
209
|
+
#### Type-safe props
|
|
173
210
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
```py
|
|
177
|
-
from typing import Literal, Any
|
|
211
|
+
```python
|
|
212
|
+
from typing import Any, Literal
|
|
178
213
|
from casp.component_decorator import component
|
|
214
|
+
from casp.html_attrs import get_attributes, merge_classes
|
|
179
215
|
|
|
180
|
-
ButtonVariant = Literal["default", "
|
|
181
|
-
ButtonSize = Literal["default", "sm", "lg"]
|
|
216
|
+
ButtonVariant = Literal["default", "outline", "destructive"]
|
|
182
217
|
|
|
183
218
|
@component
|
|
184
|
-
def Button(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
# merge classes + attrs here
|
|
191
|
-
return f"<button>...</button>"
|
|
219
|
+
def Button(children: Any = "", variant: ButtonVariant = "default", **props) -> str:
|
|
220
|
+
incoming_class = props.pop("class", "")
|
|
221
|
+
attrs = get_attributes({
|
|
222
|
+
"class": merge_classes(f"btn btn-{variant}", incoming_class),
|
|
223
|
+
}, props)
|
|
224
|
+
return f'<button {attrs}>{children}</button>'
|
|
192
225
|
```
|
|
193
226
|
|
|
194
|
-
|
|
195
|
-
|
|
227
|
+
#### Template-backed components (when UI is richer)
|
|
228
|
+
|
|
229
|
+
`Counter.py`:
|
|
196
230
|
|
|
197
|
-
```
|
|
231
|
+
```python
|
|
198
232
|
from casp.component_decorator import component, render_html
|
|
199
233
|
|
|
200
234
|
@component
|
|
201
|
-
def Counter(
|
|
202
|
-
return render_html("
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
### Reactivity (PulsePoint)
|
|
208
|
-
|
|
209
|
-
Caspian is built on **PulsePoint**, a lightweight reactive DOM engine, plus Caspian-specific helpers for full-stack workflows.
|
|
210
|
-
|
|
211
|
-
Core directives/primitives include:
|
|
212
|
-
|
|
213
|
-
- `pp-component`, `pp-spread`, `pp-ref`, `pp-for`, `pp.state`, `pp.effect`, `pp.ref`, `pp-ignore`
|
|
214
|
-
|
|
215
|
-
#### `pp.rpc(functionName, data?)`
|
|
216
|
-
|
|
217
|
-
The bridge to your Python backend. Caspian handles:
|
|
218
|
-
|
|
219
|
-
- smart serialization (JSON ↔ FormData when `File` is present)
|
|
220
|
-
- auto-redirects when server returns redirect headers
|
|
221
|
-
- `X-CSRF-Token` injection for security
|
|
222
|
-
|
|
223
|
-
#### `searchParams`
|
|
224
|
-
|
|
225
|
-
A reactive wrapper around `URLSearchParams` that updates the URL without full reloads.
|
|
226
|
-
|
|
227
|
-
#### Navigation
|
|
228
|
-
|
|
229
|
-
Caspian intercepts internal `<a>` links for client-side navigation; for programmatic navigation use:
|
|
230
|
-
|
|
231
|
-
```js
|
|
232
|
-
pp.redirect("/dashboard");
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## Backend: Async Server Actions (RPC)
|
|
238
|
-
|
|
239
|
-
Decorate `async def` functions with `@rpc`, then call them from the client using `pp.rpc()`.
|
|
240
|
-
|
|
241
|
-
**Backend (`src/app/todos/index.py`)**
|
|
242
|
-
|
|
243
|
-
```py
|
|
244
|
-
from casp.rpc import rpc
|
|
245
|
-
from casp.validate import Validate
|
|
246
|
-
from src.lib.prisma.db import prisma
|
|
247
|
-
|
|
248
|
-
@rpc()
|
|
249
|
-
async def create_todo(title):
|
|
250
|
-
if Validate.with_rules(title, "required|min:3") is not True:
|
|
251
|
-
raise ValueError("Title must be at least 3 chars")
|
|
252
|
-
|
|
253
|
-
new_todo = await prisma.todo.create(data={
|
|
254
|
-
"title": title,
|
|
255
|
-
"completed": False
|
|
256
|
-
})
|
|
257
|
-
return new_todo.to_dict()
|
|
258
|
-
|
|
259
|
-
@rpc(require_auth=True)
|
|
260
|
-
async def delete_todo(id, _current_user_id=None):
|
|
261
|
-
await prisma.todo.delete(where={"id": id})
|
|
262
|
-
return {"success": True}
|
|
235
|
+
def Counter(label: str = "Clicks") -> str:
|
|
236
|
+
return render_html(__file__, {"label": label})
|
|
263
237
|
```
|
|
264
238
|
|
|
265
|
-
|
|
239
|
+
`Counter.html`:
|
|
266
240
|
|
|
267
241
|
```html
|
|
268
|
-
<
|
|
269
|
-
<
|
|
270
|
-
<button>
|
|
271
|
-
</form>
|
|
242
|
+
<div>
|
|
243
|
+
<h3>[[ label ]]</h3>
|
|
244
|
+
<button onclick="setCount(count + 1)">{count}</button>
|
|
272
245
|
|
|
273
|
-
<script>
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
e.preventDefault();
|
|
278
|
-
const data = Object.fromEntries(new FormData(e.target));
|
|
279
|
-
|
|
280
|
-
const newTodo = await pp.rpc("create_todo", data);
|
|
281
|
-
setTodos([newTodo, ...todos]);
|
|
282
|
-
e.target.reset();
|
|
283
|
-
}
|
|
284
|
-
</script>
|
|
246
|
+
<script>
|
|
247
|
+
const [count, setCount] = pp.state(0);
|
|
248
|
+
</script>
|
|
249
|
+
</div>
|
|
285
250
|
```
|
|
286
251
|
|
|
287
252
|
---
|
|
288
253
|
|
|
289
|
-
|
|
254
|
+
### PulsePoint reactivity
|
|
290
255
|
|
|
291
|
-
|
|
256
|
+
PulsePoint is the default reactive frontend layer for Caspian. Key APIs:
|
|
292
257
|
|
|
293
|
-
|
|
258
|
+
| API | Description |
|
|
259
|
+
| ---------------------------------- | ------------------------------------------- |
|
|
260
|
+
| `pp.state(initial)` | Returns `[value, setValue]` |
|
|
261
|
+
| `pp.effect(callback, deps?)` | Runs after render; returns cleanup function |
|
|
262
|
+
| `pp.layoutEffect(callback, deps?)` | Runs synchronously after DOM mutation |
|
|
263
|
+
| `pp.ref(initialValue?)` | Returns `{ current }` |
|
|
264
|
+
| `pp.createContext(defaultValue)` | Creates a context token |
|
|
265
|
+
| `<Context.Provider value="{...}">` | Provide context to descendants |
|
|
266
|
+
| `pp.context(token)` | Read context in a descendant |
|
|
267
|
+
| `pp.portal(ref, target?)` | Portal rendering to a ref target |
|
|
268
|
+
| `pp.rpc(name, data?, options?)` | Call a backend RPC action |
|
|
269
|
+
| `pp.redirect(url)` | SPA-aware navigation |
|
|
294
270
|
|
|
295
|
-
|
|
296
|
-
model User {
|
|
297
|
-
id String @id @default(cuid())
|
|
298
|
-
email String @unique
|
|
299
|
-
name String?
|
|
300
|
-
posts Post[]
|
|
301
|
-
createdAt DateTime @default(now())
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
model Post {
|
|
305
|
-
id String @id @default(cuid())
|
|
306
|
-
title String
|
|
307
|
-
published Boolean @default(false)
|
|
308
|
-
author User @relation(fields: [authorId], references: [id])
|
|
309
|
-
authorId String
|
|
310
|
-
}
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### Client usage
|
|
314
|
-
|
|
315
|
-
```py
|
|
316
|
-
from src.lib.prisma.db import prisma
|
|
271
|
+
#### `pp.rpc(functionName, data?)`
|
|
317
272
|
|
|
318
|
-
|
|
319
|
-
```
|
|
273
|
+
The bridge to your Python backend. Caspian handles:
|
|
320
274
|
|
|
321
|
-
|
|
275
|
+
- Smart serialization (JSON ↔ FormData when `File` is present)
|
|
276
|
+
- CSRF token injection via `X-CSRF-Token`
|
|
277
|
+
- Auto-redirects when server returns redirect headers
|
|
278
|
+
- Upload progress callbacks when `onUploadProgress` is provided
|
|
322
279
|
|
|
323
280
|
---
|
|
324
281
|
|
|
325
|
-
|
|
282
|
+
### Authentication (session-based, secure defaults)
|
|
326
283
|
|
|
327
|
-
|
|
284
|
+
Configure auth in `main.py` and customize settings in `src/lib/auth/auth_config.py`.
|
|
328
285
|
|
|
329
|
-
|
|
286
|
+
| Method | Description |
|
|
287
|
+
| ---------------------------------- | ----------------------------- |
|
|
288
|
+
| `auth.sign_in(data, redirect_to?)` | Sign in a user |
|
|
289
|
+
| `auth.sign_out(redirect_to?)` | Sign out (RPC-first) |
|
|
290
|
+
| `auth.is_authenticated()` | Check current session |
|
|
291
|
+
| `auth.get_payload()` | Get user payload from session |
|
|
330
292
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
- default redirects
|
|
293
|
+
```python
|
|
294
|
+
from casp.auth import Auth, GoogleProvider, GithubProvider, configure_auth
|
|
295
|
+
from src.lib.auth.auth_config import build_auth_settings
|
|
335
296
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
- `auth.sign_out(redirect_to?)`
|
|
340
|
-
- `auth.is_authenticated()`
|
|
341
|
-
- `auth.get_payload()`
|
|
297
|
+
configure_auth(build_auth_settings())
|
|
298
|
+
Auth.set_providers(GithubProvider(), GoogleProvider())
|
|
299
|
+
```
|
|
342
300
|
|
|
343
301
|
---
|
|
344
302
|
|
|
345
303
|
## CLI reference
|
|
346
304
|
|
|
347
|
-
### Create
|
|
305
|
+
### Create a new project
|
|
348
306
|
|
|
349
307
|
```bash
|
|
350
|
-
npx create-caspian-app
|
|
308
|
+
npx create-caspian-app my-app
|
|
309
|
+
npx create-caspian-app my-app --starter-kit=fullstack
|
|
310
|
+
npx create-caspian-app my-app --tailwindcss --typescript --prisma
|
|
351
311
|
```
|
|
352
312
|
|
|
353
313
|
### Useful flags
|
|
354
314
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
315
|
+
| Flag | Description |
|
|
316
|
+
| --------------------- | ---------------------------------------------- |
|
|
317
|
+
| `--backend-only` | Skip frontend assets |
|
|
318
|
+
| `--tailwindcss` | Enable Tailwind CSS |
|
|
319
|
+
| `--prisma` | Enable Prisma ORM |
|
|
320
|
+
| `--mcp` | Enable MCP server scaffolding |
|
|
321
|
+
| `--typescript` | Enable TypeScript tooling |
|
|
322
|
+
| `--starter-kit=<kit>` | Use a preset (basic, fullstack, api, realtime) |
|
|
323
|
+
| `-y` | Non-interactive mode |
|
|
360
324
|
|
|
361
|
-
###
|
|
325
|
+
### Update existing project
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
npx casp update project
|
|
329
|
+
npx casp update project --tag beta
|
|
330
|
+
npx casp update project --version 1.2.3 -y
|
|
331
|
+
```
|
|
362
332
|
|
|
363
|
-
|
|
333
|
+
### ORM regeneration (after schema changes)
|
|
364
334
|
|
|
365
335
|
```bash
|
|
336
|
+
npx prisma migrate dev
|
|
337
|
+
npx prisma generate
|
|
338
|
+
npx prisma db seed
|
|
366
339
|
npx ppy generate
|
|
367
340
|
```
|
|
368
341
|
|
|
369
|
-
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Project structure
|
|
370
345
|
|
|
371
|
-
```bash
|
|
372
|
-
npx casp update project
|
|
373
346
|
```
|
|
347
|
+
my-app/
|
|
348
|
+
├── main.py # FastAPI entry point
|
|
349
|
+
├── caspian.config.json # Feature flags
|
|
350
|
+
├── prisma/
|
|
351
|
+
│ ├── schema.prisma
|
|
352
|
+
│ └── seed.ts
|
|
353
|
+
├── src/
|
|
354
|
+
│ ├── app/ # File-system routes
|
|
355
|
+
│ │ ├── layout.html # Root layout
|
|
356
|
+
│ │ ├── index.html # Home page
|
|
357
|
+
│ │ └── users/
|
|
358
|
+
│ │ └── [id]/
|
|
359
|
+
│ │ └── index.html # /users/:id
|
|
360
|
+
│ ├── components/ # Reusable UI components
|
|
361
|
+
│ │ └── ui/
|
|
362
|
+
│ │ └── Button.py
|
|
363
|
+
│ └── lib/ # Non-UI helpers
|
|
364
|
+
│ ├── auth/auth_config.py
|
|
365
|
+
│ └── prisma/
|
|
366
|
+
│ └── db.py
|
|
367
|
+
├── public/ # Static assets
|
|
368
|
+
└── settings/ # BrowserSync config
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Key conventions
|
|
374
372
|
|
|
375
|
-
|
|
373
|
+
- **UI routes:** `index.html` for markup, optional `index.py` for backend logic
|
|
374
|
+
- **Section layouts:** `layout.html` for the wrapper, optional `layout.py` for props
|
|
375
|
+
- **Components:** `src/components/` for reusable UI; `src/lib/` for helpers and services
|
|
376
|
+
- **`<!-- @import ... -->`:** Must appear above the single authored root element
|
|
377
|
+
- **Single-root rule:** Every template must have exactly one top-level parent node with any owned `<script>` inside it
|
|
376
378
|
|
|
377
379
|
---
|
|
378
380
|
|
|
379
381
|
## Built-in icon workflow (ppicons)
|
|
380
382
|
|
|
381
|
-
Caspian integrates **ppicons** (Lucide-based), offering 1,500+ icons
|
|
383
|
+
Caspian integrates **ppicons** (Lucide-based), offering 1,500+ icons:
|
|
382
384
|
|
|
383
385
|
```bash
|
|
384
386
|
npx ppicons add Rocket
|
|
@@ -387,33 +389,31 @@ npx ppicons add Rocket
|
|
|
387
389
|
Then use in HTML:
|
|
388
390
|
|
|
389
391
|
```html
|
|
390
|
-
<!-- @import { Rocket } from ../lib/ppicons -->
|
|
391
|
-
<
|
|
392
|
+
<!-- @import { Rocket } from "../lib/ppicons" -->
|
|
393
|
+
<x-rocket class="w-6 h-6 text-primary" />
|
|
392
394
|
```
|
|
393
395
|
|
|
394
396
|
---
|
|
395
397
|
|
|
396
|
-
##
|
|
398
|
+
## Recommended VS Code extensions
|
|
397
399
|
|
|
398
|
-
|
|
400
|
+
For the best development experience:
|
|
399
401
|
|
|
400
|
-
-
|
|
401
|
-
-
|
|
402
|
-
-
|
|
403
|
-
-
|
|
404
|
-
- `public/` — static assets served directly
|
|
402
|
+
- **Caspian Official Framework Support** — component snippets and autocomplete
|
|
403
|
+
- **Python** — Python language support
|
|
404
|
+
- **Prisma** — Schema formatting and highlighting
|
|
405
|
+
- **Tailwind CSS IntelliSense** — Class completion and sorting
|
|
405
406
|
|
|
406
407
|
---
|
|
407
408
|
|
|
408
|
-
##
|
|
409
|
+
## Learn more
|
|
409
410
|
|
|
410
|
-
|
|
411
|
+
- Documentation: [caspian.tsnc.tech/docs](https://caspian.tsnc.tech/docs)
|
|
412
|
+
- PulsePoint docs: [pulsepoint.tsnc.tech](https://pulsepoint.tsnc.tech)
|
|
413
|
+
- ppicons library: [ppicons.tsnc.tech](https://ppicons.tsnc.tech)
|
|
411
414
|
|
|
412
415
|
---
|
|
413
416
|
|
|
414
|
-
##
|
|
417
|
+
## License
|
|
415
418
|
|
|
416
|
-
|
|
417
|
-
- Site: [caspian.tsnc.tech](https://caspian.tsnc.tech)
|
|
418
|
-
- PulsePoint docs: [pulsepoint.tsnc.tech](https://pulsepoint.tsnc.tech)
|
|
419
|
-
- ppicons library: [ppicons.tsnc.tech](https://ppicons.tsnc.tech)
|
|
419
|
+
MIT
|