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 CHANGED
@@ -1,70 +1,114 @@
1
1
  # Caspian — The Native Python Web Framework for the Reactive Web
2
2
 
3
- Caspian is a highperformance, **FastAPI-powered** fullstack framework that brings **reactive UI** to Python without forcing a JavaScript backend. It combines:
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
- - A **Hybrid Frontend Engine**: start with zero-build HTML, then upgrade to **Vite + NPM + TypeScript** when needed
7
- - **Direct async RPC** (ZeroAPI): call Python functions from the browser via `pp.rpc()`
8
- - **Filesystem routing** with nested layouts and dynamic routes
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
- - A secure, session-based **auth system** and built-in security defaults
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
- ### 1) Requirements
17
+ ### Requirements
17
18
 
18
- - **Node.js**: v22.13.0+
19
+ - **Node.js**: v24.13.1+
19
20
  - **Python**: v3.14.0+
20
21
 
21
- ### 2) Create an app (interactive wizard)
22
+ ### Create an app (interactive wizard)
22
23
 
23
24
  ```bash
24
25
  npx create-caspian-app@latest
25
26
  ```
26
27
 
27
- Example prompts you’ll see in the wizard:
28
+ The wizard walks through the main project options:
28
29
 
29
30
  - Project name
30
- - Tailwind CSS
31
- - Prisma ORM
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
- ### 3) Run dev server
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 Reactive Python looks like
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
- A Caspian page can be plain HTML with reactive directives, plus a small `<script>` block for state.
49
+ ### Route template (`src/app/todos/index.html`)
47
50
 
48
51
  ```html
49
- <!-- src/app/todos/index.html -->
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
- <!-- Import Python Components -->
52
- <!-- @import { Badge } from ../components/ui -->
77
+ ### Backend RPC (`src/app/todos/index.py`)
53
78
 
54
- <div class="flex gap-2 mb-4">
55
- <Badge variant="default">Tasks: {todos.length}</Badge>
56
- </div>
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
- <!-- Reactive Loop -->
59
- <ul>
60
- <template pp-for="todo in todos">
61
- <li key="{todo.id}" class="p-2 border-b">{todo.title}</li>
62
- </template>
63
- </ul>
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
- // State initialized by Python backend automatically
67
- const [todos, setTodos] = pp.state([[todos]]);
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 (DI, middleware, validation, etc.) without a separate JS backend.
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
- ### ZeroAPI server actions (RPC)
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
- ### Filesystem routing with nested layouts
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
- ### Security defaults and authentication
139
+ ### PulsePoint reactive runtime
96
140
 
97
- Built-in CSRF protection, strict Origin validation, HttpOnly cookies, and a session-based auth model with RBAC support.
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
- - **Caspian Official Framework Support** (component autocompletion + snippets)
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 uses **file-system routing** under `src/app`:
153
+ Caspian follows the same mental model as the Next.js App Router. Your directory structure becomes your URL structure.
116
154
 
117
- | File Path | URL Path |
155
+ | File | URL |
118
156
  | ------------------------------- | ------------- |
119
157
  | `src/app/index.html` | `/` |
120
- | `src/app/about/index.py` | `/about` |
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
- ```txt
126
- src/app/users/[id]/index.py -> /users/123
163
+ ```
164
+ src/app/users/[id]/index.html -> /users/123
127
165
  ```
128
166
 
129
167
  #### Catch-all segments
130
168
 
131
- ```txt
132
- src/app/docs/[...slug]/index.py -> /docs/getting-started/setup
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
- ```txt
138
- src/app/(auth)/login/index.py -> /login
139
- src/app/(auth)/register/index.py -> /register
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
- - Nested: e.g., `/dashboard/settings` inherits root + dashboard layout automatically
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 (best for buttons, badges, icons, etc.)
195
+ #### Atomic component
156
196
 
157
- ```py
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
- **DX speed tip:** the VS Code extension can generate boilerplate via a snippet like `caspcom`.
209
+ #### Type-safe props
173
210
 
174
- #### Type-safe props (TypeScript-like autocomplete)
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", "destructive", "outline"]
181
- ButtonSize = Literal["default", "sm", "lg"]
216
+ ButtonVariant = Literal["default", "outline", "destructive"]
182
217
 
183
218
  @component
184
- def Button(
185
- children: Any = "",
186
- variant: ButtonVariant = "default",
187
- size: ButtonSize = "default",
188
- **props,
189
- ) -> str:
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
- **HTML templates for complex UI**
195
- For larger layouts or reactive UIs, bridge to an HTML file:
227
+ #### Template-backed components (when UI is richer)
228
+
229
+ `Counter.py`:
196
230
 
197
- ```py
231
+ ```python
198
232
  from casp.component_decorator import component, render_html
199
233
 
200
234
  @component
201
- def Counter(**props):
202
- return render_html("Counter.html", **props)
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
- **Frontend (`src/app/todos/index.html`)**
239
+ `Counter.html`:
266
240
 
267
241
  ```html
268
- <form onsubmit="add(event)">
269
- <input name="title" required />
270
- <button>Add</button>
271
- </form>
242
+ <div>
243
+ <h3>[[ label ]]</h3>
244
+ <button onclick="setCount(count + 1)">{count}</button>
272
245
 
273
- <script>
274
- const [todos, setTodos] = pp.state([]);
275
-
276
- async function add(e) {
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
- ## Database: Prisma ORM
254
+ ### PulsePoint reactivity
290
255
 
291
- Caspian uses a Prisma schema as the single source of truth and generates a typed Python client. It is designed to translate Prisma syntax into optimized SQL without requiring the heavy Prisma Engine binary.
256
+ PulsePoint is the default reactive frontend layer for Caspian. Key APIs:
292
257
 
293
- **Schema (`prisma/schema.prisma`)**
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
- ```prisma
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
- users = prisma.user.find_many()
319
- ```
273
+ The bridge to your Python backend. Caspian handles:
320
274
 
321
- The docs also describe connection pooling and common CRUD patterns (create, find, update, delete), plus aggregations and transactions.
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
- ## Authentication (session-based, secure defaults)
282
+ ### Authentication (session-based, secure defaults)
326
283
 
327
- Caspian includes session-based authentication with HttpOnly cookies and RBAC-friendly conventions.
284
+ Configure auth in `main.py` and customize settings in `src/lib/auth/auth_config.py`.
328
285
 
329
- **Configure auth in `main.py`**
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
- - global protection toggle (`is_all_routes_private`)
332
- - public routes whitelist
333
- - auth routes (signin/signup)
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
- The global `auth` object provides:
337
-
338
- - `auth.sign_in(data, redirect_to?)`
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 projects
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
- - `--backend-only` skip frontend assets
356
- - `--tailwindcss` Tailwind CSS v4 + PostCSS + `globals.css`
357
- - `--typescript` TypeScript support with Vite + `tsconfig.json`
358
- - `--mcp` Model Context Protocol server scaffolding (AI Agents)
359
- - `--prisma` Prisma ORM integration + sample schema
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
- ### Code generation
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
- Generate strict Python data classes (Pydantic) from your Prisma schema:
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
- ### Updating the project
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
- Tip: use `excludeFiles` in `caspian.config.json` to prevent overwrites during updates.
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 and an instant add command:
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
- <Rocket class="w-6 h-6 text-primary" />
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
- ## Project structure (generated by the CLI)
398
+ ## Recommended VS Code extensions
397
399
 
398
- High-level layout:
400
+ For the best development experience:
399
401
 
400
- - `main.py`FastAPI app & ASGI entry
401
- - `caspian.config.json`project config
402
- - `prisma/`schema + seed scripts
403
- - `src/` app routes, pages, styles, shared libs
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
- ## License
409
+ ## Learn more
409
410
 
410
- MIT
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
- ## Learn more
417
+ ## License
415
418
 
416
- - Documentation: [Caspian docs](https://caspian.tsnc.tech/docs)
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