caspian-utils 0.0.1 → 0.0.2

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.
@@ -16,6 +16,8 @@ This page summarizes the main Caspian CLI workflows for creating projects, gener
16
16
 
17
17
  ## Overview
18
18
 
19
+ The current workspace includes a local `prisma` binary, but it does not include local `create-caspian-app`, `casp`, or `ppy` binaries under `node_modules/.bin`. Treat the scaffold and project-update commands below as external `npx` workflows rather than project-local executables.
20
+
19
21
  Use Caspian CLI commands for three main tasks:
20
22
 
21
23
  - Create a new application.
@@ -52,21 +54,21 @@ Common scaffold flags include:
52
54
 
53
55
  - `--backend-only` for API-only projects without frontend assets
54
56
  - `--tailwindcss` to install Tailwind CSS support
55
- - `--typescript` to add TypeScript and Vite support
57
+ - `--typescript` to add TypeScript support and any scaffold-specific TypeScript build/config files
56
58
  - `--mcp` to initialize a Model Context Protocol server for AI agents
57
59
  - `--prisma` to initialize Prisma ORM support
58
60
 
59
61
  ## Code Generation
60
62
 
61
- When your Prisma schema changes, use the generation command shown in the Caspian CLI docs:
63
+ When your Prisma schema changes in this workspace, regenerate the client with the local Prisma CLI:
62
64
 
63
65
  ```bash
64
- npx ppy generate
66
+ npx prisma generate
65
67
  ```
66
68
 
67
- This flow regenerates the Python Prisma client based on `prisma/schema.prisma`.
69
+ This flow regenerates the Prisma client defined by `generator client` in `prisma/schema.prisma`. In the current workspace, that generator uses `prisma-client-js`.
68
70
 
69
- In Prisma-enabled Caspian apps, this is the step that keeps the shared imports under `src/lib/prisma/` aligned with the schema.
71
+ This workspace already includes an app-owned Python database layer in `src/lib/prisma/`, so reuse that package for Python-side database access instead of creating a second helper.
70
72
 
71
73
  See `database.md` for the full Prisma workflow, including `.env`, `prisma.config.ts`, migrations, and async usage patterns.
72
74
 
@@ -78,7 +80,7 @@ Use the project update command for existing Caspian apps:
78
80
  npx casp update project
79
81
  ```
80
82
 
81
- This command updates framework-managed project files and can overwrite entry points, styles, or configuration files if they are not protected.
83
+ This command updates framework-managed project files and can overwrite entry points, styles, or configuration files if they are not protected. The `casp` binary is not bundled locally in this workspace, so verify the external CLI package before automating this command.
82
84
 
83
85
  ## Configuration
84
86
 
@@ -111,7 +113,7 @@ If an AI agent is deciding which command flow to use, apply these rules first.
111
113
  - Use `npx create-caspian-app@latest` when the user is creating a new project.
112
114
  - Use `npx casp update project` only for an existing Caspian project.
113
115
  - Read `caspian.config.json` before running update commands.
114
- - Use `npx ppy generate` after Prisma schema changes.
115
- - Check `database.md` when the task involves Prisma setup, schema updates, or generated client files under `src/lib/prisma/`.
116
+ - Use `npx prisma generate` after Prisma schema changes in this workspace.
117
+ - Check `database.md` when the task involves Prisma setup, schema updates, or the current workspace's schema, migration, and seed tooling.
116
118
  - Check [routing.md](./routing.md) before generating or modifying route folders under `src/app/`.
117
119
  - Check [project-structure.md](./project-structure.md) before placing generated files into the project.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Database
3
- description: Use Prisma in Caspian with the generated async Python client, schema-first workflow, and the shared imports under `src/lib/prisma/`.
3
+ description: Use Prisma in this workspace through `prisma/schema.prisma`, `prisma.config.ts`, migrations, seeding, and the generated client defined by the local schema.
4
4
  related:
5
5
  title: Related docs
6
6
  description: Use the project structure guide to place database files correctly, then use the fetch-data guide when Prisma calls need to power route rendering or RPC actions.
@@ -12,9 +12,9 @@ related:
12
12
  - /docs/index
13
13
  ---
14
14
 
15
- This page documents the default Caspian database workflow with Prisma ORM.
15
+ This page documents the Prisma workflow present in this workspace.
16
16
 
17
- Treat Prisma as the default persistence layer when a Caspian app includes database support. The Prisma schema is the source of truth, the generated Python client is the runtime interface, and route code should import the shared client from `src.lib.prisma` instead of constructing ad hoc database connections inside each page or RPC action.
17
+ This repo currently uses Prisma for schema management, migrations, and seed tooling on the Node side. The local `prisma/schema.prisma` uses `generator client { provider = "prisma-client-js" }`, `prisma.config.ts` seeds through `tsx prisma/seed.ts`, and this workspace already includes an app-owned Python database layer under `src/lib/prisma/`. If Python routes or RPC actions need database access, reuse that package instead of creating another helper.
18
18
 
19
19
  ## Overview
20
20
 
@@ -22,9 +22,9 @@ The standard Prisma flow in Caspian is:
22
22
 
23
23
  1. Define models in `prisma/schema.prisma`.
24
24
  2. Configure `DATABASE_URL` in `.env`.
25
- 3. Run `npx ppy generate` after schema changes.
26
- 4. Import the generated async client from `src.lib.prisma.db` or `src.lib.prisma`.
27
- 5. Use Prisma calls inside `page()`, `layout()`, or `@rpc()` actions.
25
+ 3. Run `npx prisma generate` after schema changes.
26
+ 4. Use the generated client from Node-side tooling such as `prisma/seed.ts`.
27
+ 5. Reuse the shared Python database layer in `src/lib/prisma/` when Python route or RPC code needs database access.
28
28
 
29
29
  Use this workflow instead of writing raw SQL first. Drop to raw SQL only when a query cannot be expressed clearly with the generated client.
30
30
 
@@ -68,7 +68,7 @@ Keep schema in `prisma/schema.prisma`, connection secrets in `.env`, and generat
68
68
 
69
69
  ## Define Your Schema
70
70
 
71
- Model your data in `prisma/schema.prisma`. This file is the source of truth for both the database structure and the generated Python client API.
71
+ Model your data in `prisma/schema.prisma`. This file is the source of truth for the database structure used by both the generated Node Prisma client and the app-owned Python layer in `src/lib/prisma/`.
72
72
 
73
73
  Example:
74
74
 
@@ -79,7 +79,7 @@ datasource db {
79
79
  }
80
80
 
81
81
  generator client {
82
- provider = "prisma-client-py"
82
+ provider = "prisma-client-js"
83
83
  }
84
84
 
85
85
  model User {
@@ -99,13 +99,13 @@ model Post {
99
99
  }
100
100
  ```
101
101
 
102
- After changing the schema, regenerate the Python client before using new models or fields in app code.
102
+ After changing the schema, run `npx prisma generate` so the generated Node Prisma client stays in sync with the schema. If the Python layer in `src/lib/prisma/` depends on the updated shape, regenerate or refresh that application-owned code too.
103
103
 
104
104
  ## Command Reference
105
105
 
106
106
  Use these commands for the normal Prisma lifecycle in Caspian:
107
107
 
108
- - `npx ppy generate` compiles `schema.prisma` into the generated Python client. Run this after every schema change.
108
+ - `npx prisma generate` compiles `schema.prisma` into the generated Prisma client. Run this after every schema change.
109
109
  - `npx prisma migrate dev` creates and applies a development migration.
110
110
  - `npx prisma migrate deploy` applies pending migrations in deployment environments.
111
111
  - `npx prisma db push` syncs schema changes without creating a migration file, which is useful for prototyping.
@@ -114,69 +114,45 @@ Use these commands for the normal Prisma lifecycle in Caspian:
114
114
 
115
115
  Default rule:
116
116
 
117
- - Use `npx ppy generate` every time the schema changes.
117
+ - Use `npx prisma generate` every time the schema changes.
118
118
  - Use migrations for tracked application changes.
119
119
  - Use `db push` only when you intentionally want a faster, migration-free prototype loop.
120
120
 
121
- ## Generated Python Client Files
121
+ ## Prisma Files In This Workspace
122
122
 
123
- In a Prisma-enabled Caspian app, the generated and shared Python imports live under `src/lib/prisma/`.
123
+ The current repo ships Prisma files in these locations:
124
124
 
125
- ### `src/lib/prisma/db.py`
125
+ ### `prisma/schema.prisma`
126
126
 
127
- This module exposes the shared Prisma client instance used by route code and RPC actions.
127
+ This file is the schema source of truth. It currently defines a `prisma-client-js` generator.
128
128
 
129
- Typical usage:
129
+ ### `prisma.config.ts`
130
130
 
131
- ```python
132
- from src.lib.prisma.db import prisma
133
-
134
- users = await prisma.user.find_many()
135
- ```
131
+ This file configures the schema path, migrations path, and the seed entry point. In this workspace it runs seeds through `tsx prisma/seed.ts`.
136
132
 
137
- Use this import as the default way to access the database. Do not instantiate new Prisma clients inside each request handler unless you are solving a very specific lifecycle problem.
133
+ ### `prisma/seed.ts`
138
134
 
139
- ### `src/lib/prisma/models.py`
135
+ This file is the current example of code that imports and uses the generated Prisma client.
140
136
 
141
- This module contains the generated Python model types derived from `prisma/schema.prisma`.
137
+ ### `node_modules/@prisma/client/`
142
138
 
143
- Use it when you need explicit model imports for typing, serialization, or helper code that works with generated record objects.
139
+ After `npx prisma generate`, Prisma writes the generated JavaScript client into the normal `@prisma/client` package location.
144
140
 
145
- Typical usage pattern:
146
-
147
- ```python
148
- from src.lib.prisma import models
149
-
150
- def as_public_user(user: models.User) -> dict:
151
- return {
152
- "id": user.id,
153
- "email": user.email,
154
- "name": user.name,
155
- }
156
- ```
141
+ ### `src/lib/prisma/`
157
142
 
158
- Treat these classes as generated artifacts. Change the schema, then regenerate, instead of editing model definitions by hand.
143
+ This workspace already includes an app-owned async Python database package that exports `prisma`, `PrismaClient`, generated models, and helper types.
159
144
 
160
- ### `src/lib/prisma/__init__.py`
145
+ If Python route or RPC code needs database access, import from `src.lib.prisma` and keep that import path explicit in application code.
161
146
 
162
- This module is the package entry point for Prisma imports.
147
+ ## Python Route Usage
163
148
 
164
- If it re-exports the shared client and generated model helpers, application code can use a shorter import shape such as:
165
-
166
- ```python
167
- from src.lib.prisma import prisma, models
168
- ```
169
-
170
- Prefer this package-level import when it keeps route code clearer. Prefer direct imports from `db.py` when you want to make the client source explicit.
171
-
172
- ## Async Client Usage
173
-
174
- The Prisma client in Caspian should be treated as async-first. Use `await` for database operations.
149
+ This workspace already ships an app-owned Python Prisma-style layer under `src/lib/prisma/`. Treat it as async-first and reuse it from route and RPC code.
175
150
 
176
151
  Example:
177
152
 
178
153
  ```python
179
- from src.lib.prisma.db import prisma
154
+ from casp.layout import render_page
155
+ from src.lib.prisma import prisma
180
156
 
181
157
  async def page():
182
158
  users = await prisma.user.find_many()
@@ -189,9 +165,10 @@ async def page():
189
165
  Prisma calls fit naturally in:
190
166
 
191
167
  - `async def page()` for first-render data
192
- - `async def layout()` for shared section data
193
168
  - `@rpc()` actions for browser-triggered reads and writes
194
169
 
170
+ Keep Prisma I/O out of `layout.py` in the current runtime because `casp.layout` calls `layout()` synchronously.
171
+
195
172
  See `fetch-data.md` for the recommended route-render versus RPC split.
196
173
 
197
174
  ## CRUD Examples
@@ -301,7 +278,7 @@ print(stats["_count"]["_all"])
301
278
  ### Transactions
302
279
 
303
280
  ```python
304
- async with prisma.tx() as tx:
281
+ async with prisma.transaction() as tx:
305
282
  user = await tx.user.create(
306
283
  data={
307
284
  "email": "alice@example.com",
@@ -330,7 +307,7 @@ Use raw SQL sparingly. Prefer the generated Prisma API when the query can be exp
330
307
  ## Recommended Project Rules
331
308
 
332
309
  - Keep the schema in `prisma/schema.prisma` and regenerate the client after changes.
333
- - Import the shared client from `src.lib.prisma.db` or `src.lib.prisma`, not from ad hoc connection code scattered across routes.
310
+ - Reuse `src/lib/prisma/` for Python-side database access instead of creating a second bridge.
334
311
  - Keep reusable database helpers in `src/lib/`, and keep route-specific orchestration in `src/app/`.
335
312
  - Use `await` with Prisma operations.
336
313
  - Convert Prisma objects to template-safe dictionaries when rendering HTML.
@@ -343,9 +320,9 @@ If an AI agent is working on a Caspian app with Prisma enabled, apply these rule
343
320
 
344
321
  - Treat Prisma as the default ORM and persistence layer.
345
322
  - Read `prisma/schema.prisma` before proposing model, relation, or field changes.
346
- - Run `npx ppy generate` after schema changes so the Python client matches the schema.
347
- - Import the shared client from `src.lib.prisma.db` or the `src.lib.prisma` package entry point.
348
- - Treat `src/lib/prisma/models.py` as generated model output, not hand-authored business logic.
323
+ - Run `npx prisma generate` after schema changes.
324
+ - Read `prisma.config.ts` and `prisma/seed.ts` when you need the current workspace's Prisma tooling examples.
325
+ - Reuse the existing `src/lib/prisma/` package when the Python app needs database access.
349
326
  - Put reusable database helpers in `src/lib/`; keep route and RPC orchestration in `src/app/`.
350
- - Use `page()` or `layout()` for first-render reads and `@rpc()` plus `pp.rpc()` for browser-triggered reads and writes.
327
+ - Use `async def page()` for first-render reads. Keep `layout()` synchronous in the current runtime, and use `@rpc()` plus `pp.rpc()` for browser-triggered reads and writes.
351
328
  - Check `fetch-data.md` for route versus RPC guidance and `validation.md` before writing public mutations.
@@ -23,7 +23,7 @@ Treat RPC as the default way for browser code to talk to Python in Caspian. Do n
23
23
 
24
24
  Caspian has two main data-loading paths:
25
25
 
26
- - `page()` or `layout()` for server-side data needed during the initial render
26
+ - `page()` for initial-render data, plus `layout()` for synchronous shared props or metadata during the render
27
27
  - `@rpc()` plus `pp.rpc()` for interactive fetches after the page is already loaded
28
28
 
29
29
  In practice, most pages use both:
@@ -34,7 +34,7 @@ In practice, most pages use both:
34
34
 
35
35
  ## Default Data Rule
36
36
 
37
- - Use `page()` or `layout()` for data required before HTML renders.
37
+ - Use `page()` for async or route-level data required before HTML renders, and use `layout()` only for synchronous shared props or metadata.
38
38
  - Use `@rpc()` on the server and `pp.rpc()` in PulsePoint code for all browser-triggered data work after first render.
39
39
  - Keep custom REST or other endpoint patterns as explicit exceptions, not the baseline Caspian approach.
40
40
 
@@ -67,10 +67,10 @@ If a route's first-render HTML is public and stable enough to reuse across reque
67
67
  Notes:
68
68
 
69
69
  - Prefer `async def page()` when your database or API client is async-capable.
70
- - Put shared section-level data in `layout.py` when multiple child routes need the same payload.
70
+ - Put shared section-level props in `layout.py` when multiple child routes need the same synchronous payload. The current layout engine does not await `layout()`.
71
71
  - Keep reusable database or API clients under `src/lib/`; keep route-specific orchestration in `src/app/`.
72
72
 
73
- If the data source is Prisma, see `database.md` for schema, generation, and shared client import conventions.
73
+ If the data source is Prisma, see `database.md` for the current workspace's schema, migration, and generation workflow. This scaffold does not generate Python-side Prisma helpers under `src/lib/` by default.
74
74
 
75
75
  ## Interactive Data With RPC
76
76
 
@@ -231,7 +231,7 @@ For initial route rendering with `render_page(...)`, prefer passing plain templa
231
231
 
232
232
  ## Recommended Decision Rule
233
233
 
234
- Use `page()` or `layout()` when the data is part of the page render. Use `@rpc()` plus `pp.rpc()` when the browser needs to ask the server for more data after the page is already visible.
234
+ Use `page()` when async or route-specific data is part of the page render. Use `layout()` for synchronous shared props or metadata. Use `@rpc()` plus `pp.rpc()` when the browser needs to ask the server for more data after the page is already visible.
235
235
 
236
236
  A common pattern is:
237
237
 
@@ -246,7 +246,8 @@ If the first-render HTML is expensive to produce and safe to share between visit
246
246
  If an AI agent is choosing how to load data in Caspian, apply these rules first.
247
247
 
248
248
  - Put first-render data loading in `src/app/**/index.py`.
249
- - Put shared section data in `layout.py` when multiple child routes need it.
249
+ - Put shared section props in `layout.py` only when multiple child routes need the same synchronous data.
250
+ - Keep async I/O in `page()` or `@rpc()` because the current layout engine does not await `layout()`.
250
251
  - Treat RPC as the default read and write layer between PulsePoint code and Python route logic.
251
252
  - Use `@rpc()` for backend functions that should be callable from the browser.
252
253
  - Use `pp.rpc()` for client-side calls; do not prefer older `pp.fetchFunction()` wording.
@@ -24,17 +24,17 @@ When generating or editing a Caspian app, treat these as the default choices unl
24
24
 
25
25
  The local AI-aware docs for this workspace live here:
26
26
 
27
- - `dist/docs/`
27
+ - `node_modules/caspian-utils/dist/docs/`
28
28
 
29
- The packaged Caspian docs distributed by the framework live here:
29
+ The packaged Caspian docs distributed by the current toolchain also live here:
30
30
 
31
- - `node_modules/caspian/dist/docs/`
31
+ - `node_modules/caspian-utils/dist/docs/`
32
32
 
33
33
  ## Available Documents
34
34
 
35
35
  - `installation.md` - First-time setup flow for creating a new Caspian application
36
36
  - `commands.md` - Main Caspian CLI workflows for project creation, generation, updates, and config-aware maintenance
37
- - `database.md` - Prisma ORM setup, generated async Python client usage, and the shared `src/lib/prisma/` imports
37
+ - `database.md` - Prisma schema, migration, seed, and client-generation workflow for the current workspace, plus Python-side helper caveats
38
38
  - `auth.md` - Session-backed authentication with `casp.auth`, centralized `auth_config.py`, decorators, RBAC, and OAuth provider helpers
39
39
  - `pulsepoint.md` - Default reactive frontend runtime contract for component scripts, state, effects, directives, and client-side behaviors
40
40
  - `fetch-data.md` - Initial server-side data loading and browser-triggered RPC flows with `pp.rpc()`, streaming, uploads, and auth-aware actions
@@ -51,10 +51,10 @@ If an AI tool needs Caspian project documentation, start with this directory and
51
51
 
52
52
  Preferred lookup order:
53
53
 
54
- 1. Read `dist/docs/index.md` to discover available local docs.
54
+ 1. Read `node_modules/caspian-utils/dist/docs/index.md` to discover available local docs.
55
55
  2. Read `database.md` for Prisma setup and ORM usage, `auth.md` for session auth and route protection, `pulsepoint.md` for reactive frontend work, `fetch-data.md` for data flows, `state.md` for transient request-scoped state, `cache.md` for page caching, and `validation.md` for input boundaries.
56
56
  3. Prefer local docs before generating code, commands, or migration guidance.
57
- 4. Check `node_modules/caspian/dist/docs/` for packaged Caspian docs when local docs need more detail.
57
+ 4. Check `node_modules/caspian-utils/dist/docs/` for packaged Caspian docs when local docs need more detail.
58
58
  5. Only fall back to upstream documentation when local and packaged markdown do not cover the topic.
59
59
 
60
60
  ## Maintenance
@@ -14,7 +14,9 @@ This page documents the first-time Caspian setup flow for new applications.
14
14
 
15
15
  ## Overview
16
16
 
17
- Caspian provides a CLI that scaffolds a production-ready project with a FastAPI backend and a PulsePoint-based reactive frontend workflow.
17
+ Caspian provides a scaffold flow for new apps with a FastAPI backend and a PulsePoint-based reactive frontend workflow.
18
+
19
+ In this workspace, the local `caspian-utils` package ships documentation only, so scaffold commands are resolved through external `npx` packages rather than project-local binaries.
18
20
 
19
21
  ## Default App Stack
20
22
 
@@ -28,8 +30,8 @@ The scaffolded Caspian baseline is:
28
30
 
29
31
  Install the supported runtimes before creating a project.
30
32
 
31
- - Node.js `v24.14.0` or newer
32
- - Python `v3.14.0` or newer
33
+ - Node.js with `npm` and `npx` available
34
+ - Python `v3.11.0` or newer
33
35
 
34
36
  You can verify your environment with:
35
37
 
@@ -49,9 +51,8 @@ npx create-caspian-app@latest
49
51
  The interactive wizard walks through the main project options, including:
50
52
 
51
53
  - Project name
52
- - Tailwind CSS support
53
- - Prisma ORM setup
54
- - Swagger API documentation
54
+ - Feature toggles such as backend-only mode, Tailwind CSS, Prisma, MCP, and TypeScript
55
+ - Other scaffold options exposed by the current CLI version
55
56
 
56
57
  ## Recommended VS Code Setup
57
58
 
@@ -75,6 +76,8 @@ cd my-app
75
76
  npm run dev
76
77
  ```
77
78
 
79
+ In this workspace, `npm run dev` is backed by BrowserSync plus PostCSS watchers, not a Vite dev server.
80
+
78
81
  ## After Setup
79
82
 
80
83
  Once the project is scaffolded:
@@ -84,7 +84,8 @@ Example:
84
84
  ```python
85
85
  from casp.layout import Metadata, render_page
86
86
 
87
- async def page(slug: str):
87
+ async def page(params: dict):
88
+ slug = params["slug"]
88
89
  product_name = f"Product {slug.capitalize()}"
89
90
 
90
91
  Metadata(
@@ -99,6 +100,8 @@ async def page(slug: str):
99
100
  return render_page(__file__, {"name": product_name})
100
101
  ```
101
102
 
103
+ In the current router, dynamic path params arrive as a single `params` dict passed to `page()`.
104
+
102
105
  Set dynamic metadata before calling `render_page(...)` so the route renders with the correct head values.
103
106
 
104
107
  Inside the same module, runtime `Metadata(...)` overrides matching keys from the module-level static `metadata` object.
@@ -32,7 +32,7 @@ For public pages that can safely reuse rendered HTML, Caspian also supports rout
32
32
  - `main.py` is the application entry point.
33
33
  - `caspian.config.json` is the core feature configuration file.
34
34
  - `.venv/Lib/site-packages/casp/` contains the installed Caspian framework core.
35
- - `node_modules/caspian/dist/docs/` contains the packaged Caspian docs.
35
+ - `node_modules/caspian-utils/dist/docs/` contains the packaged Caspian docs.
36
36
 
37
37
  ## Example Layout
38
38
 
@@ -62,7 +62,7 @@ my-app/
62
62
  site-packages/
63
63
  casp/
64
64
  node_modules/
65
- caspian/
65
+ caspian-utils/
66
66
  dist/
67
67
  docs/
68
68
  ```
@@ -83,19 +83,13 @@ See `routing.md` for the full App Router-style rules for dynamic segments, route
83
83
 
84
84
  Use this folder for shared helpers, reusable validators, RPC-facing service wrappers, reusable UI utilities, and app-level support code.
85
85
 
86
- When Prisma ORM is enabled, this folder also contains the shared database client imports under `src/lib/prisma/`.
86
+ This workspace already includes an app-owned Python database layer under `src/lib/prisma/`. Reuse that package for Python-side data access and keep any additional shared database helpers in `src/lib/`.
87
87
 
88
- ### `src/lib/prisma/`
88
+ ### Shared Database Helpers
89
89
 
90
- When a Caspian app includes Prisma support, this folder contains the shared ORM imports used by route code and RPC actions.
90
+ If your Python routes or RPC actions need reusable database access code, keep that helper layer under `src/lib/` and extend the existing `src/lib/prisma/` package.
91
91
 
92
- Typical files include:
93
-
94
- - `src/lib/prisma/db.py` for the shared Prisma client instance
95
- - `src/lib/prisma/models.py` for generated Python model types
96
- - `src/lib/prisma/__init__.py` for package-level re-exports such as `prisma` and `models`
97
-
98
- See `database.md` for the Prisma-specific workflow, generation step, and usage patterns.
92
+ In this workspace, Prisma schema and seed files live under `prisma/`, while the Python-side adapter is application-owned code under `src/lib/prisma/`.
99
93
 
100
94
  ### `src/lib/auth/`
101
95
 
@@ -161,9 +155,9 @@ Notable internal files include:
161
155
  - `.venv/Lib/site-packages/casp/cache_handler.py` for route-level cache declarations, cache manifest handling, disk-backed HTML writes, and invalidation internals
162
156
  - `.venv/Lib/site-packages/casp/validate.py` for direct validators, rule-based validation, sanitization, and file-validation internals
163
157
 
164
- ### `node_modules/caspian/dist/docs/`
158
+ ### `node_modules/caspian-utils/dist/docs/`
165
159
 
166
- The packaged Caspian documentation location distributed with the framework.
160
+ The packaged Caspian documentation location distributed with the current toolchain.
167
161
 
168
162
  ## AI Routing Notes
169
163
 
@@ -176,7 +170,7 @@ If an AI agent is deciding where to make changes, use these rules first.
176
170
  - Use `@rpc()` in route/backend code and `pp.rpc()` in client code for browser-triggered data flows.
177
171
  - Use `casp.cache_handler` when a route's first-render HTML should be reused safely across requests.
178
172
  - Use `casp.validate` at route and RPC boundaries, and move reusable validators into `src/lib/` when multiple routes share them.
179
- - Use `database.md` when the task involves Prisma schema changes, generated client usage, or the shared files under `src/lib/prisma/`.
173
+ - Use `database.md` when the task involves Prisma schema changes, migrations, seed logic, or workspace-specific database helper conventions.
180
174
  - Put authentication configuration in `src/lib/auth/auth_config.py`.
181
175
  - Put auth bootstrap, session middleware, and provider registration changes in `main.py`.
182
176
  - Put database models and seed logic in `prisma/`.
@@ -188,6 +182,6 @@ If an AI agent is deciding where to make changes, use these rules first.
188
182
  - Use `.venv/Lib/site-packages/casp/layout.py` when investigating or documenting Caspian routing, layout, or metadata internals.
189
183
  - Use `.venv/Lib/site-packages/casp/cache_handler.py` when investigating or documenting Caspian page-caching internals.
190
184
  - Use `.venv/Lib/site-packages/casp/validate.py` when investigating or documenting Caspian validation internals.
191
- - Look in `node_modules/caspian/dist/docs/` when you need the packaged framework docs.
185
+ - Look in `node_modules/caspian-utils/dist/docs/` when you need the packaged framework docs.
192
186
 
193
187
  Check [index.md](./index.md) first if you need to choose between local Caspian docs.
@@ -1,19 +1,19 @@
1
1
  ---
2
2
  title: PulsePoint Runtime Guide
3
- description: Learn how AI agents should use PulsePoint as the default reactive frontend contract in Caspian, including the current TypeScript runtime, component script rules, and supported directives.
3
+ description: Learn how AI agents should use PulsePoint as the default reactive frontend contract in Caspian, including the bundled runtime loaded from `public/js/main.js` and implemented in `public/js/pp-reactive-v2.js`, component script rules, and supported directives.
4
4
  related:
5
5
  title: Related docs
6
- description: Read the route, component, data-fetching, and TypeScript docs alongside the PulsePoint runtime contract.
6
+ description: Read the routing, data-fetching, and project-structure docs alongside the PulsePoint runtime contract.
7
7
  links:
8
- - /docs/pages-and-layouts
9
- - /docs/import-component
8
+ - /docs/routing
10
9
  - /docs/fetch-data
11
- - /docs/typescript
10
+ - /docs/project-structure
11
+ - /docs/index
12
12
  ---
13
13
 
14
14
  ## Purpose
15
15
 
16
- This file documents the PulsePoint runtime that is actually implemented in the current TypeScript source under `ts/` and verified by `ts/__tests__/`. Treat it as the working contract for AI-generated code.
16
+ This file documents the PulsePoint runtime that is currently shipped in `public/js/pp-reactive-v2.js` and loaded by `public/js/main.js`. Treat it as the working contract for AI-generated code.
17
17
 
18
18
  If a task involves `pp.state`, `pp.effect`, `pp.layoutEffect`, `pp-ref`, `pp-spread`, `pp-for`, context, portals, SPA navigation, or component boundary behavior, read this page first and keep generated code aligned with the runtime implemented in this repo.
19
19
 
@@ -32,9 +32,9 @@ When a Caspian page needs reactive browser behavior, use PulsePoint.
32
32
  ## Source layer vs raw runtime
33
33
 
34
34
  - Source authoring under `src/` may use convenience syntax that is transformed before it reaches the browser.
35
- - This page describes the raw browser runtime implemented in `ts/`.
36
- - When source-layer examples conflict with the TypeScript runtime, follow the TypeScript runtime.
37
- - In the raw runtime, component logic uses `<script>`, not plain `<script>`.
35
+ - This page describes the bundled browser runtime shipped in `public/js/pp-reactive-v2.js`.
36
+ - When source-layer examples conflict with the bundled runtime, follow the bundled runtime.
37
+ - In a `pp-component` root, component logic must live in `<script>`, not plain `<script>`.
38
38
 
39
39
  ## Runtime shape
40
40
 
@@ -51,15 +51,15 @@ Important:
51
51
 
52
52
  ## Component roots and scripts
53
53
 
54
- - Each runtime component root should have at most one component script.
55
- - The runtime only treats `<script>` as component logic.
54
+ - Each runtime component root should have at most one `<script>` block.
55
+ - The runtime only treats `script` as component logic.
56
56
  - The script lookup walks the current root and skips nested `pp-component` boundaries, so a parent does not consume a child component's script.
57
57
  - If multiple matching scripts exist in the same root, the first matching owned script wins. Generate one script per root.
58
58
  - A scriptless component root still mounts and can receive props, refs, events, and nested children, but it has no local runtime scope beyond its props.
59
59
  - Component scripts are plain JavaScript executed with `new Function(...)`. Do not use `import`, `export`, or top-level `await` inside them.
60
60
  - The runtime auto-returns supported top-level bindings from the script. Do not rely on manual `return { ... }` objects.
61
61
  - `pp.props` contains the current prop bag for the component.
62
- - `pp.props.children` contains the root's initial inner HTML before the owning `script` is removed from the render template.
62
+ - `pp.props.children` contains the root's initial inner HTML before the owning `script` block is removed from the render template.
63
63
 
64
64
  Bindings exported to the template:
65
65
 
@@ -122,11 +122,11 @@ Global helpers exposed on the `pp` singleton:
122
122
 
123
123
  Notes:
124
124
 
125
- - The global `pp` singleton auto-mounts once `pp-utilities.js` is loaded and the DOM is ready. Manual `pp.mount()` is still safe because it short-circuits after the first mount.
125
+ - The global `pp` singleton auto-mounts once `public/js/main.js` loads the bundled runtime and the DOM is ready. Manual `pp.mount()` is still safe because it short-circuits after the first mount.
126
126
  - `pp.state` setters accept either a value or an updater function.
127
127
  - `pp.effect` and `pp.layoutEffect` are cleanup-style hooks. Returned promises are not awaited.
128
128
  - `pp.portal(ref)` defaults to `document.body` when no target is provided.
129
- - Older docs may call the RPC helper `pp.fetchFunction()`. In the current TypeScript runtime the implemented global API is `pp.rpc()`.
129
+ - Older docs may call the RPC helper `pp.fetchFunction()`. In the current bundled runtime the implemented global API is `pp.rpc()`.
130
130
  - Keep template-facing bindings at the top level so the AST-based exporter can see them.
131
131
 
132
132
  ## Context
@@ -188,8 +188,8 @@ Nested components:
188
188
 
189
189
  - Nested `pp-component` roots are treated as component boundaries during DOM reconciliation.
190
190
  - Parent prop interpolation still runs on nested child root attributes before the child refreshes.
191
- - Nested roots that contain their own `script` are masked during parent template compilation.
192
- - Scriptless nested component roots are not fully masked during parent template compilation in the current source. Avoid generating child-local interpolations inside a nested root unless that child has its own `script`.
191
+ - Nested roots that contain their own `script` block are masked during parent template compilation.
192
+ - Scriptless nested component roots are not fully masked during parent template compilation in the current source. Avoid generating child-local interpolations inside a nested root unless that child has its own `script` block.
193
193
 
194
194
  ## Template expressions and attributes
195
195
 
@@ -323,15 +323,15 @@ Notes:
323
323
  Use these rules when generating or editing PulsePoint runtime code:
324
324
 
325
325
  - Treat PulsePoint as the default reactive frontend for Caspian app code.
326
- - Use the current TypeScript runtime under `ts/` when it is available.
326
+ - Use the bundled runtime contract in `public/js/pp-reactive-v2.js`.
327
327
  - Generate unique `pp-component` values per live instance.
328
- - Use only `<script>` for raw runtime component logic.
328
+ - Use only `<script>` for component logic inside a `pp-component` root.
329
329
  - Keep template-facing variables at top level.
330
330
  - Use `pp.createContext`, `pp.context`, and `pp.provideContext` for context. Do not invent `pp-context`.
331
331
  - Keep `pp-for` on `<template>` and use plain `key`.
332
332
  - Use native `on*` attributes, not framework-specific event syntax.
333
333
  - Use refs and portals only through the implemented `pp` APIs.
334
- - Use `pp.rpc()` for the raw TypeScript runtime API instead of older `pp.fetchFunction()` wording.
334
+ - Use `pp.rpc()` for the bundled runtime API instead of older `pp.fetchFunction()` wording.
335
335
  - Avoid generating internal runtime attributes.
336
336
  - Avoid scriptless nested components when the child template contains its own bindings.
337
337
 
@@ -348,16 +348,16 @@ Do not generate these unless the current source explicitly adds support:
348
348
  - `pp-dynamic-script`
349
349
  - `pp-dynamic-meta`
350
350
  - `pp-dynamic-link`
351
- - plain `<script>` for raw runtime component logic inside a component root
351
+ - plain `<script>` for component logic inside a `pp-component` root
352
352
  - `pp.fetchFunction()` as the current raw runtime helper name
353
- - made-up hooks, directives, or globals not present in the current TypeScript source
353
+ - made-up hooks, directives, or globals not present in the current bundled runtime
354
354
 
355
355
  ## Review notes
356
356
 
357
357
  These are current runtime caveats that matter for authors and AI tools:
358
358
 
359
359
  - `pp-component` is the registry key for instances, state, parent tracking, and templates. Treat it as unique per mounted root.
360
- - Nested roots without their own `script` are not fully isolated during parent template compilation.
360
+ - Nested roots without their own `script` block are not fully isolated during parent template compilation.
361
361
  - The global `pp` singleton auto-mounts on DOM ready, and `pp.mount()` is idempotent.
362
362
  - `pp.effect` and `pp.layoutEffect` are cleanup-style hooks. Their callbacks are not promise-aware.
363
363
  - `pp.context()` resolves through ancestor components, not the current component's own pending providers.
@@ -365,4 +365,4 @@ These are current runtime caveats that matter for authors and AI tools:
365
365
 
366
366
  ## Final reminder
367
367
 
368
- If a feature is not implemented in the current TypeScript runtime source, do not invent it.
368
+ If a feature is not implemented in the current bundled runtime, do not invent it.
@@ -14,7 +14,7 @@ related:
14
14
 
15
15
  Caspian follows the same mental model as the Next.js App Router: routes live under `src/app`, folders define URL segments, layouts nest automatically, and special folder names control grouping and dynamic matching.
16
16
 
17
- The main difference is the file types. Instead of `page.tsx` and `layout.tsx`, Caspian uses `index.html`, `index.py`, `layout.html`, and optional Python companions for async server-side logic.
17
+ The main difference is the file types. Instead of `page.tsx` and `layout.tsx`, Caspian uses `index.html`, `index.py`, `layout.html`, and optional Python companions for server-side logic.
18
18
 
19
19
  ## Overview
20
20
 
@@ -26,7 +26,7 @@ Start with these rules:
26
26
  - Use `index.html` for a template-only route.
27
27
  - Use `index.py` when the route needs metadata or async server-side logic.
28
28
  - Use `layout.html` to wrap child routes.
29
- - Use `layout.py` when a layout needs async data before rendering.
29
+ - Use `layout.py` when a layout needs shared synchronous props or metadata before rendering.
30
30
 
31
31
  Use [cache.md](./cache.md) when an `index.py` route also needs declarative page caching via `Cache(...)`.
32
32
 
@@ -111,6 +111,18 @@ Wrap a folder name in brackets to make it variable.
111
111
 
112
112
  These segments are compiled into FastAPI path parameters for efficient route matching.
113
113
 
114
+ In the current `main.py` router, path params are collected into a single dict and passed as the first positional argument to `page()`. Matching query params can still be injected by name, and `request` is passed by keyword when declared.
115
+
116
+ Example:
117
+
118
+ ```python
119
+ from casp.layout import render_page
120
+
121
+ async def page(params: dict):
122
+ user_id = params["id"]
123
+ return render_page(__file__, {"user_id": user_id})
124
+ ```
125
+
114
126
  ### Catch-all Segments
115
127
 
116
128
  Use an ellipsis inside brackets to match multiple path parts.
@@ -164,15 +176,15 @@ Example root layout:
164
176
 
165
177
  ### `layout.py`
166
178
 
167
- If a layout needs async data, add a `layout.py` file next to the HTML layout.
179
+ If a layout needs shared synchronous props or metadata, add a `layout.py` file next to the HTML layout.
168
180
 
169
181
  Example:
170
182
 
171
183
  ```python
172
184
  from casp.auth import auth
173
185
 
174
- async def layout(context_data):
175
- user = auth.get_payload()
186
+ def layout(context_data):
187
+ user = auth.get_payload()
176
188
 
177
189
  return {
178
190
  "user": user,
@@ -182,6 +194,8 @@ async def layout(context_data):
182
194
 
183
195
  `context_data` includes URL parameters such as dynamic route values.
184
196
 
197
+ `layout()` currently runs synchronously in `casp.layout`. If you need async I/O, load it in `page()` instead of `layout.py`.
198
+
185
199
  Use [metadata.md](./metadata.md) when a layout also needs SEO defaults. Return dictionaries from `layout()` for visual or template props, and use `Metadata(...)` for title, description, and social tags.
186
200
 
187
201
  ## Recommended Structure
@@ -220,7 +234,7 @@ If an AI agent is choosing where to add or update route code, apply these rules
220
234
  - Use folder names to model URL segments.
221
235
  - Use `index.html` for route templates and `index.py` for route-level async logic.
222
236
  - Use [cache.md](./cache.md) when an `index.py` route should opt into page-level HTML caching.
223
- - Use `layout.html` for shared wrappers and `layout.py` for layout-level async data.
237
+ - Use `layout.html` for shared wrappers and `layout.py` for layout-level synchronous props or metadata.
224
238
  - Use [metadata.md](./metadata.md) when a route or layout needs SEO fields.
225
239
  - Use `[segment]` for single dynamic parameters.
226
240
  - Use `[...segment]` for catch-all route matching.
@@ -64,6 +64,8 @@ Important implementation detail:
64
64
 
65
65
  In other words, cross-request persistence depends on the surrounding Caspian middleware keeping `request.state.session` available and in sync with session storage.
66
66
 
67
+ In this workspace's current `main.py`, `SessionMiddleware` exposes `request.session`, but the middleware stack does not mirror that into `request.state.session`. Treat persistence as opt-in until you add that bridge explicitly.
68
+
67
69
  ## Request Lifecycle
68
70
 
69
71
  The current request lifecycle is:
@@ -76,7 +78,7 @@ The current request lifecycle is:
76
78
 
77
79
  That last step matters. In the current implementation, non-wire requests start by clearing the loaded state and writing the empty state back to the session bucket.
78
80
 
79
- Treat the current behavior as request-local state plus framework-managed transient persistence for wire-driven flows. If you expect full-page redirect flash semantics, verify the exact middleware and request path in your local Caspian version before depending on it.
81
+ Treat the current behavior in this repo as request-local state plus partially wired transient persistence for wire-driven flows. If you expect full-page redirect flash semantics or cross-request state reuse, verify the exact middleware bridge in your local Caspian version before depending on it.
80
82
 
81
83
  You usually do not initialize this manually in route code. The current auth middleware docs already show `StateManager.init(request)` running during request setup.
82
84
 
@@ -219,6 +221,7 @@ The current implementation resets `_state_listeners` inside `StateManager.init(.
219
221
  - `AttributeDict.__getattr__` raises `AttributeError` for missing keys and `__setattr__` writes back into the dict.
220
222
  - Because persistence uses JSON, keep stored values simple: strings, numbers, booleans, lists, dicts, and `None`.
221
223
  - The current lifecycle resets loaded state on non-wire requests, so verify redirect and flash behavior against the actual request type you are using.
224
+ - In this repo's current middleware stack, `request.state.session` is not populated from `request.session`, so saved state may not survive into a later request unless you add that bridge.
222
225
 
223
226
  ## Recommended Usage Pattern
224
227
 
@@ -259,6 +262,7 @@ If an AI agent is deciding how to use transient state in a Caspian app, apply th
259
262
  - Do not assume recursive `AttributeDict` wrapping for nested dicts.
260
263
  - Treat `subscribe(...)` listeners as request-local and short-lived.
261
264
  - Be careful with full-page redirect assumptions because `init(request)` clears loaded state on non-wire requests.
265
+ - Do not assume cross-request persistence in this repo until middleware copies `request.session` into `request.state.session`.
262
266
  - Use PulsePoint state for client interactivity and `StateManager` for server request flows.
263
267
  - Check [auth.md](./auth.md) for middleware ordering and request initialization details.
264
268
  - Check [project-structure.md](./project-structure.md) before deciding whether a transient-state helper belongs next to a route or in `src/lib/`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caspian-utils",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Caspian tooling",
5
5
  "main": "index.js",
6
6
  "scripts": {