caspian-utils 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,257 @@
1
+ ---
2
+ title: Cache
3
+ description: Cache rendered Caspian route HTML with `casp.cache_handler`, `Cache`, and `CacheHandler`, using route-level TTLs, file-system storage, and explicit invalidation for public read-heavy pages.
4
+ related:
5
+ title: Related docs
6
+ description: Use the routing guide to place route-level cache declarations correctly, then pair cache with fetch-data when deciding what can be safely served from reused HTML.
7
+ links:
8
+ - /docs/routing
9
+ - /docs/fetch-data
10
+ - /docs/project-structure
11
+ - /docs/index
12
+ ---
13
+
14
+ This page explains the current Caspian page-cache API for route-level HTML caching, disk-backed cache storage, TTL handling, and manual invalidation.
15
+
16
+ Treat `casp.cache_handler` as the default page-caching layer in Caspian app code. Use it for public, read-heavy routes whose rendered HTML can be safely reused across requests. Do not cache personalized, auth-sensitive, or rapidly changing HTML unless you fully control invalidation and visibility.
17
+
18
+ ## Overview
19
+
20
+ Caspian exposes page caching through `casp.cache_handler`.
21
+
22
+ Import the API like this:
23
+
24
+ ```python
25
+ from casp.cache_handler import Cache, CacheHandler
26
+ ```
27
+
28
+ The current installed implementation lives in `.venv/Lib/site-packages/casp/cache_handler.py`.
29
+
30
+ The real API surface is:
31
+
32
+ - declarative route config with `Cache(ttl=..., enabled=...)`
33
+ - disk-backed HTML lookup with `CacheHandler.serve_cache(...)`
34
+ - disk-backed HTML writes with `CacheHandler.save_cache(...)`
35
+ - selective invalidation with `CacheHandler.invalidate_by_uri(...)`
36
+ - full or targeted resets with `CacheHandler.reset_cache(...)`
37
+
38
+ Use caching when a route is expensive to render but the final HTML is stable enough to reuse, such as marketing pages, blog indexes, docs pages, and public content pages.
39
+
40
+ ## Default Caching Rule
41
+
42
+ - Use `Cache(...)` at module scope in a route's `index.py` when you want that route to participate in Caspian's page cache.
43
+ - Cache public HTML that is safe to share between visitors.
44
+ - Avoid caching dashboards, auth callbacks, request-specific error states, flash-message flows, or any page whose HTML changes per user.
45
+ - Invalidate cached pages after writes, publishes, deletes, or admin actions that change what those routes should render.
46
+ - Treat page caching as HTML reuse, not as a replacement for database caching or RPC response caching.
47
+
48
+ ## Declarative Route Config
49
+
50
+ The `Cache` dataclass is the project-facing API you define in route code.
51
+
52
+ Current fields:
53
+
54
+ - `ttl: int = 600`
55
+ - `enabled: bool = True`
56
+
57
+ Example:
58
+
59
+ ```python
60
+ from casp.layout import render_page
61
+ from casp.cache_handler import Cache
62
+
63
+ cache_settings = Cache(ttl=3600, enabled=True)
64
+
65
+ async def page():
66
+ return render_page(__file__)
67
+ ```
68
+
69
+ You can also rely on the current auto-registration behavior and call `Cache(...)` bare at module scope:
70
+
71
+ ```python
72
+ from casp.layout import render_page
73
+ from casp.cache_handler import Cache
74
+
75
+ Cache(ttl=7200, enabled=True)
76
+
77
+ async def page():
78
+ return render_page(__file__)
79
+ ```
80
+
81
+ Implementation notes from the installed file:
82
+
83
+ - `Cache.__post_init__()` inspects the caller frame.
84
+ - When `Cache(...)` is called at module scope, it auto-registers itself as `cache_settings` in that module's globals.
85
+ - That magic registration only happens for module-level calls where the caller code object name is `<module>`.
86
+
87
+ Prefer the explicit `cache_settings = Cache(...)` form in maintained project code because it makes the route intent obvious to readers and tooling.
88
+
89
+ To disable caching for a route explicitly:
90
+
91
+ ```python
92
+ from casp.cache_handler import Cache
93
+
94
+ cache_settings = Cache(enabled=False)
95
+ ```
96
+
97
+ Use this for routes that are public but too volatile or sensitive to serve from cached HTML.
98
+
99
+ ## How The Disk Cache Works
100
+
101
+ `CacheHandler` stores cached HTML on disk under the current working directory.
102
+
103
+ Current paths:
104
+
105
+ - cache directory: `caches/`
106
+ - manifest file: `caches/cache_manifest.json`
107
+
108
+ The request lifecycle is conceptually:
109
+
110
+ 1. A request arrives for a URI.
111
+ 2. `CacheHandler.serve_cache(uri, default_ttl=600)` checks `cache_manifest.json` for that exact URI.
112
+ 3. If the manifest entry is missing, the file is missing, or the entry has expired, the request is treated as a cache miss.
113
+ 4. On a hit, Caspian returns the cached HTML string directly.
114
+ 5. On a miss, the route renders normally and the framework can persist the rendered HTML with `CacheHandler.save_cache(...)`.
115
+
116
+ Filename generation is path-based:
117
+
118
+ - `/` becomes `index.html`
119
+ - other paths are lowercased, non-alphanumeric characters are replaced with `_`, and the result is saved as `*.html`
120
+
121
+ Examples:
122
+
123
+ - `/docs/cache` becomes `docs_cache.html`
124
+ - `/blog/post-1` becomes `blog_post-1.html`
125
+
126
+ ## `CacheHandler` Methods
127
+
128
+ The installed `CacheHandler` class currently provides these main helpers:
129
+
130
+ | Method | Purpose | Return value |
131
+ | --- | --- | --- |
132
+ | `ensure_cache_dir()` | Creates `caches/` and `cache_manifest.json` if needed. | None |
133
+ | `serve_cache(uri, default_ttl=600)` | Returns cached HTML when the entry exists and is still fresh. | Cached `str` or `None` |
134
+ | `save_cache(uri, content, ttl=0)` | Writes the HTML file and updates the manifest entry. | None |
135
+ | `invalidate_by_uri(uris)` | Removes one or more cached URIs and their HTML files. | None |
136
+ | `reset_cache(uri=None)` | Removes a specific cached URI or clears the whole cache directory. | None |
137
+
138
+ Example manual usage:
139
+
140
+ ```python
141
+ from casp.cache_handler import CacheHandler
142
+
143
+ html = CacheHandler.serve_cache("/docs/cache", default_ttl=600)
144
+ if html is not None:
145
+ return html
146
+
147
+ CacheHandler.invalidate_by_uri("/docs/cache")
148
+ CacheHandler.invalidate_by_uri([
149
+ "/blog",
150
+ "/blog/python",
151
+ ])
152
+
153
+ CacheHandler.reset_cache("/docs/cache")
154
+ # Or clear everything:
155
+ # CacheHandler.reset_cache()
156
+ ```
157
+
158
+ In normal route code, `CacheHandler.serve_cache(...)` and `save_cache(...)` are usually framework-driven internals. App code most often interacts with `Cache(...)` and with invalidation helpers after content changes.
159
+
160
+ ## Invalidate After Mutations
161
+
162
+ If a cached page depends on mutable content, invalidate it after the write succeeds.
163
+
164
+ Example:
165
+
166
+ ```python
167
+ from casp.rpc import rpc
168
+ from casp.cache_handler import CacheHandler
169
+
170
+ @rpc(require_auth=True)
171
+ async def publish_post(slug: str):
172
+ # Save post changes here.
173
+
174
+ CacheHandler.invalidate_by_uri([
175
+ "/blog",
176
+ f"/blog/{slug}",
177
+ ])
178
+
179
+ return {"success": True}
180
+ ```
181
+
182
+ Use this pattern when:
183
+
184
+ - an RPC action updates a blog post, docs page, or product page
185
+ - an admin publish flow changes public route output
186
+ - a route index depends on records that were just created or deleted
187
+
188
+ For browser-triggered writes and invalidation flows, pair this page with [fetch-data.md](./fetch-data.md).
189
+
190
+ ## TTL Behavior
191
+
192
+ The installed implementation stores a per-entry TTL in the manifest and compares it to the saved timestamp.
193
+
194
+ Important details:
195
+
196
+ - `Cache.ttl` defaults to `600` seconds.
197
+ - `CacheHandler.save_cache(...)` records the `created_at` timestamp and the provided `ttl` value.
198
+ - `CacheHandler.serve_cache(...)` uses the saved TTL when it is greater than `0`.
199
+ - If the saved TTL is `0` or negative, `serve_cache(...)` falls back to its `default_ttl` argument.
200
+ - Expired entries are invalidated automatically and then treated as cache misses.
201
+
202
+ This means `ttl=0` does not mean "cache forever" in the current implementation. It means "use the caller's default TTL fallback."
203
+
204
+ ## Upstream Global Config Note
205
+
206
+ The upstream Caspian cache page also describes application-wide environment settings such as `CACHE_ENABLED` and `CACHE_TTL`.
207
+
208
+ Those settings are not parsed inside `casp.cache_handler.py` itself. Treat `Cache(...)` as the route-level override layer and treat any environment-driven defaults as framework configuration that is handled elsewhere in the stack for your specific Caspian version.
209
+
210
+ ## Current Implementation Notes
211
+
212
+ - The manifest file name is currently `cache_manifest.json`, not `manifest.json`.
213
+ - `get_filename(uri)` strips the query string before generating the HTML filename.
214
+ - The manifest itself is keyed by the exact URI string passed into `save_cache(...)` and `serve_cache(...)`.
215
+ - Because filenames ignore the query string, different query variants of the same path can map to the same HTML file name.
216
+ - `invalidate_by_uri(...)` normalizes each URI to start with `/`, so use leading-slash URIs consistently.
217
+ - `save_cache(...)`, invalidation, and write failures log to stdout with `[Cache] ...` messages.
218
+ - `reset_cache()` removes files from `caches/` and then rewrites an empty manifest.
219
+ - `Cache(...)` auto-registration only occurs at module scope. Instantiating it inside a function does not declaratively register route cache settings.
220
+
221
+ ## Recommended Usage Pattern
222
+
223
+ Validate whether the HTML is shareable first, then add cache configuration close to the route boundary.
224
+
225
+ Common placement patterns are:
226
+
227
+ - module-level `cache_settings = Cache(...)` inside `src/app/**/index.py`
228
+ - explicit invalidation inside `@rpc()` actions or admin flows after a successful write
229
+ - occasional maintenance resets through `CacheHandler.reset_cache()` in operational scripts or debugging sessions
230
+
231
+ Good candidates for page caching are:
232
+
233
+ - landing pages
234
+ - public docs pages
235
+ - blog indexes and published article pages
236
+ - public category or catalog pages whose HTML changes on a predictable cadence
237
+
238
+ Poor candidates are:
239
+
240
+ - authenticated dashboards
241
+ - per-user feeds or notification views
242
+ - forms whose server-rendered HTML includes request-specific or sensitive state
243
+ - pages that need sub-second freshness unless you have reliable invalidation hooks
244
+
245
+ ## AI Routing Notes
246
+
247
+ If an AI agent is deciding whether or how to cache a Caspian route, apply these rules first.
248
+
249
+ - Use `Cache` from `casp.cache_handler` for route-level page caching.
250
+ - Prefer `cache_settings = Cache(...)` at module scope over a bare call when writing maintained project code.
251
+ - Use `enabled=False` for pages whose HTML is personalized, auth-sensitive, or too volatile to reuse safely.
252
+ - Use `CacheHandler.invalidate_by_uri(...)` after writes that change cached public content.
253
+ - Use `CacheHandler.reset_cache()` only for targeted maintenance, debugging, or full cache clears.
254
+ - Use leading-slash URIs consistently when interacting with `CacheHandler`.
255
+ - Treat `caches/` and `caches/cache_manifest.json` as framework cache artifacts, not as source files.
256
+ - Pair this page with [fetch-data.md](./fetch-data.md) when deciding how cached first-render HTML relates to interactive RPC updates.
257
+ - Check [routing.md](./routing.md) before deciding where a route's cache declaration belongs.
@@ -0,0 +1,117 @@
1
+ ---
2
+ title: Commands
3
+ description: Use the Caspian CLI reference to scaffold projects, generate code, and update framework files without confusing first-time setup with existing-project maintenance.
4
+ related:
5
+ title: Related docs
6
+ description: Start with installation for new apps, then use the routing and structure guides to place generated files correctly.
7
+ links:
8
+ - /docs/installation
9
+ - /docs/database
10
+ - /docs/routing
11
+ - /docs/project-structure
12
+ - /docs/index
13
+ ---
14
+
15
+ This page summarizes the main Caspian CLI workflows for creating projects, generating code, and updating an existing app.
16
+
17
+ ## Overview
18
+
19
+ Use Caspian CLI commands for three main tasks:
20
+
21
+ - Create a new application.
22
+ - Generate code from your Prisma schema.
23
+ - Update framework-managed project files.
24
+
25
+ Before running update commands, review `caspian.config.json` because it controls overwrite behavior.
26
+
27
+ ## Project Creation
28
+
29
+ Use the interactive scaffold when starting a new Caspian app:
30
+
31
+ ```bash
32
+ npx create-caspian-app@latest
33
+ ```
34
+
35
+ You can also create a project with starter-kit flags:
36
+
37
+ ```bash
38
+ npx create-caspian-app my-app --starter-kit=fullstack
39
+ ```
40
+
41
+ For a custom source setup, the CLI also supports a custom starter flow:
42
+
43
+ ```bash
44
+ npx create-caspian-app my-tool --starter-kit=custom ...
45
+ ```
46
+
47
+ After scaffolding, use `routing.md` to understand how Caspian maps `src/app` folders to URLs.
48
+
49
+ ## Installation Flags
50
+
51
+ Common scaffold flags include:
52
+
53
+ - `--backend-only` for API-only projects without frontend assets
54
+ - `--tailwindcss` to install Tailwind CSS support
55
+ - `--typescript` to add TypeScript and Vite support
56
+ - `--mcp` to initialize a Model Context Protocol server for AI agents
57
+ - `--prisma` to initialize Prisma ORM support
58
+
59
+ ## Code Generation
60
+
61
+ When your Prisma schema changes, use the generation command shown in the Caspian CLI docs:
62
+
63
+ ```bash
64
+ npx ppy generate
65
+ ```
66
+
67
+ This flow regenerates the Python Prisma client based on `prisma/schema.prisma`.
68
+
69
+ In Prisma-enabled Caspian apps, this is the step that keeps the shared imports under `src/lib/prisma/` aligned with the schema.
70
+
71
+ See `database.md` for the full Prisma workflow, including `.env`, `prisma.config.ts`, migrations, and async usage patterns.
72
+
73
+ ## Update Project
74
+
75
+ Use the project update command for existing Caspian apps:
76
+
77
+ ```bash
78
+ npx casp update project
79
+ ```
80
+
81
+ This command updates framework-managed project files and can overwrite entry points, styles, or configuration files if they are not protected.
82
+
83
+ ## Configuration
84
+
85
+ The CLI reads `caspian.config.json` to decide how it should interact with the project.
86
+
87
+ Important configuration areas include:
88
+
89
+ - Project identity and root path
90
+ - Feature toggles such as backend-only, Tailwind, MCP, Prisma, and TypeScript
91
+ - Component scan directories
92
+ - `excludeFiles` rules for protecting local changes during updates
93
+
94
+ ## `excludeFiles` Strategy
95
+
96
+ Use `excludeFiles` in `caspian.config.json` to prevent the update command from overwriting files you have customized.
97
+
98
+ This is useful for protecting:
99
+
100
+ - Stylesheets
101
+ - Configuration files
102
+ - Entry-point files
103
+ - Other locally modified framework-managed files
104
+
105
+ If you exclude a file, it will be preserved during updates, but you may need to merge future framework changes into that file manually.
106
+
107
+ ## AI Routing Notes
108
+
109
+ If an AI agent is deciding which command flow to use, apply these rules first.
110
+
111
+ - Use `npx create-caspian-app@latest` when the user is creating a new project.
112
+ - Use `npx casp update project` only for an existing Caspian project.
113
+ - 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
+ - Check [routing.md](./routing.md) before generating or modifying route folders under `src/app/`.
117
+ - Check [project-structure.md](./project-structure.md) before placing generated files into the project.