@yottagraph-app/aether-instructions 1.1.15 → 1.1.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yottagraph-app/aether-instructions",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "Cursor rules, commands, and skills for Aether development",
5
5
  "files": [
6
6
  "rules",
package/rules/pref.mdc CHANGED
@@ -46,19 +46,23 @@ The backing store auto-initializes on first use — no need to call
46
46
 
47
47
  ## Local Development
48
48
 
49
- When KV credentials (`KV_REST_API_URL`, `KV_REST_API_TOKEN`) are not set
50
- (e.g. local dev without Vercel env vars), the KV server routes return
51
- `undefined` for reads and silently skip writes. Prefs will work with
52
- their default values but won't persist across page refreshes.
49
+ KV credentials are only available in deployed builds (Vercel auto-injects
50
+ them at runtime). In local dev, `getRedis()` returns `null` and KV routes
51
+ return `undefined` for reads and silently skip writes. `Pref<T>` still
52
+ works with its default value but won't persist across page refreshes.
53
53
 
54
- For full local persistence, copy the KV credentials from your Vercel
55
- project settings into your local `.env` file (or use the Portal's
56
- "Get .env file" feature).
54
+ This is expected push to `main` and test persistence on the deployed build.
55
+
56
+ **Auth dependency:** All `/api/kv/*` routes call `unsealCookie(event)` to
57
+ identify the user. In dev mode (no `NUXT_PUBLIC_AUTH0_CLIENT_SECRET` set),
58
+ this is bypassed automatically using `NUXT_PUBLIC_USER_NAME`. If you set an
59
+ Auth0 client secret without proper cookie setup, KV writes will silently
60
+ no-op.
57
61
 
58
62
  ## Direct API Alternative
59
63
 
60
64
  If you prefer not to use the `Pref<T>` class, you can call the KV
61
- routes directly:
65
+ routes directly from client-side code:
62
66
 
63
67
  ```typescript
64
68
  // Read
@@ -73,6 +77,11 @@ await $fetch('/api/kv/write', {
73
77
  });
74
78
  ```
75
79
 
80
+ These routes require the browser's auth cookie — they work from client-side
81
+ `$fetch` calls but not from server routes or external scripts. For
82
+ server-to-server KV access, use `getRedis()` from `server/utils/redis.ts`
83
+ directly.
84
+
76
85
  ## Feature-Scoped Preferences
77
86
 
78
87
  Features should namespace preferences under the app's prefix:
package/rules/server.mdc CHANGED
@@ -19,7 +19,8 @@ server/
19
19
  │ ├── kv/ # KV (Upstash Redis) CRUD — read, write, delete, documents, status
20
20
  │ └── avatar/[url].ts # Avatar image proxy
21
21
  └── utils/
22
- ├── redis.ts # Upstash Redis client init (from Vercel KV env vars)
22
+ ├── redis.ts # Upstash Redis client (lazy-init from KV_REST_API_URL)
23
+ ├── neon.ts # Neon Postgres client (lazy-init from DATABASE_URL) — present if Neon provisioned
23
24
  └── cookies.ts # Cookie handling (@hapi/iron)
24
25
  ```
25
26
 
@@ -67,35 +68,33 @@ if (redis) {
67
68
 
68
69
  Returns `null` if KV is not configured (env vars missing). Always check.
69
70
 
71
+ For client-side preferences, use `usePrefsStore()` and `Pref<T>` instead of
72
+ calling KV routes directly — see the `pref` rule.
73
+
70
74
  ## Neon Postgres
71
75
 
72
- If a Neon database is connected to the project, `DATABASE_URL` (pooled) and
73
- `DATABASE_URL_UNPOOLED` (direct) are available. Vercel auto-injects them for
74
- deployed builds; for local dev they are populated in `.env` during project
75
- init. Check `.env` for `DATABASE_URL` — if present, Postgres is ready to use.
76
+ If `DATABASE_URL` is in `.env`, Postgres is ready to use. The project init
77
+ scaffolds `server/utils/neon.ts` and installs `@neondatabase/serverless`
78
+ automatically when a Neon database is detected.
76
79
 
77
- ### Utility pattern
80
+ ### How to check
78
81
 
79
- Create `server/utils/neon.ts` following the same lazy-init pattern as
80
- `redis.ts` export a getter that returns `null` when the env var is missing:
82
+ - `DATABASE_URL` present in `.env` Postgres is connected
83
+ - `server/utils/neon.ts` exists utility is scaffolded
84
+ - If either is missing, the project wasn't provisioned with Neon (add it
85
+ from the Broadchurch Portal, then re-run `node init-project.js`)
81
86
 
82
- ```typescript
83
- import { neon, type NeonQueryFunction } from '@neondatabase/serverless';
87
+ **Local dev:** `DATABASE_URL` is not yet available for local development.
88
+ `getDb()` returns `null` when the credential is missing or invalid. Write
89
+ your server routes to handle this gracefully (return a "database not
90
+ configured" error or empty state). Push to `main` to test with a real
91
+ database on the deployed build, where credentials are auto-injected.
84
92
 
85
- let _sql: NeonQueryFunction | null = null;
93
+ ### Usage
86
94
 
87
- export function getDb(): NeonQueryFunction | null {
88
- if (_sql) return _sql;
89
- const url = process.env.DATABASE_URL;
90
- if (!url) return null;
91
- _sql = neon(url);
92
- return _sql;
93
- }
94
- ```
95
-
96
- Install the driver: `npm install @neondatabase/serverless`
97
-
98
- ### Usage in server routes
95
+ `server/utils/neon.ts` exports `getDb()` (same lazy-init pattern as
96
+ `getRedis()` in `redis.ts`): returns a query function or `null` if
97
+ `DATABASE_URL` is not set.
99
98
 
100
99
  ```typescript
101
100
  import { getDb } from '~/server/utils/neon';
@@ -109,13 +108,62 @@ export default defineEventHandler(async () => {
109
108
  });
110
109
  ```
111
110
 
112
- The driver uses tagged template literals for automatic SQL injection
111
+ The Neon driver uses tagged template literals for automatic SQL injection
113
112
  protection — `await sql\`SELECT * FROM notes WHERE id = ${id}\`` is safe.
114
113
  No ORM, no query builder, no connection pool setup needed.
115
114
 
115
+ ### Creating tables
116
+
117
+ There is no migrations framework. Use `CREATE TABLE IF NOT EXISTS` directly
118
+ in a setup route or at the top of a route that needs the table:
119
+
120
+ ```typescript
121
+ const sql = getDb()!;
122
+ await sql`CREATE TABLE IF NOT EXISTS notes (
123
+ id SERIAL PRIMARY KEY,
124
+ content TEXT NOT NULL,
125
+ created_at TIMESTAMPTZ DEFAULT NOW()
126
+ )`;
127
+ ```
128
+
129
+ For simple apps, putting the `CREATE TABLE IF NOT EXISTS` in each route that
130
+ uses the table is fine — it's a no-op after the first call. For more complex
131
+ schemas, create a `server/api/db/setup.post.ts` route that initializes all
132
+ tables.
133
+
134
+ ### If `server/utils/neon.ts` doesn't exist
135
+
136
+ Create it manually (or re-run init):
137
+
138
+ ```bash
139
+ npm install @neondatabase/serverless
140
+ ```
141
+
142
+ ```typescript
143
+ // server/utils/neon.ts
144
+ import { neon, type NeonQueryFunction } from '@neondatabase/serverless';
145
+
146
+ let _sql: NeonQueryFunction | null = null;
147
+
148
+ export function isDbConfigured(): boolean {
149
+ return Boolean(process.env.DATABASE_URL);
150
+ }
151
+
152
+ export function getDb(): NeonQueryFunction | null {
153
+ if (_sql) return _sql;
154
+ const url = process.env.DATABASE_URL;
155
+ if (!url) return null;
156
+ _sql = neon(url);
157
+ return _sql;
158
+ }
159
+ ```
160
+
116
161
  ## Key Differences from Client-Side Code
117
162
 
118
163
  - Server routes run on the server (Node.js), not in the browser
119
164
  - They have access to Redis, Neon Postgres, secrets, and server-only APIs
120
165
  - They do NOT have access to Vue composables, Vuetify, or any client-side code
121
166
  - Use `defineEventHandler`, not Vue component patterns
167
+
168
+ See `architecture` rule for the full data architecture overview, `pref` rule
169
+ for client-side KV preferences.