@nuasite/notes 0.22.2 → 0.22.4

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
@@ -6,7 +6,15 @@ A reviewer opens any page with `?nua-notes` appended to the URL, sees a sidebar
6
6
 
7
7
  ## Status
8
8
 
9
- **v0.1first usable release.** All five build phases of the original plan are shipped except Phase 5 polish (proxy/sandbox forwarding through the CMS Cloudflare Worker, replies, the agency inbox view, theming, and i18n). The local-first dev flow is feature-complete and verified end-to-end with puppeteer.
9
+ **v0.2agency mode + soft delete + history.** Adds a permission split that keeps reviewers from accidentally rewriting source files or losing the audit trail:
10
+
11
+ - A **client** (the default) can only create comments and suggestions. The Apply, Resolve, and Delete buttons are not rendered, and the dev API rejects those routes with 403.
12
+ - An **agency** (URL flag `?nua-agency`) gets the full controls: Apply suggestions to source, Resolve / Reopen, Delete (soft), Purge (hard).
13
+ - **Soft delete**: clicking Delete in agency mode flips the item to `status: 'deleted'`. The item stays on disk so the agency always sees what happened. A separate `Purge` action hard-removes it.
14
+ - **History trail**: every mutation appends a `{ at, action, role }` entry to `item.history`. The agency item card shows it in a collapsed details element. Clients can't see the history.
15
+ - The base v0.1 surface (overlay, comments, suggestions, diff, anchor re-attach, apply flow, etc.) still ships and is unchanged.
16
+
17
+ Phase 5 polish (proxy/sandbox forwarding through the CMS Cloudflare Worker, replies, the agency inbox view, theming, i18n) is still deferred.
10
18
 
11
19
  ## Quick start
12
20
 
@@ -28,32 +36,40 @@ bun run dev
28
36
  Then:
29
37
 
30
38
  - `http://localhost:4321/` — normal CMS editor view, notes is invisible
31
- - `http://localhost:4321/?nua-notes` — review mode: sidebar visible, CMS chrome hidden, click "Pick element" to comment or select text to suggest
32
-
33
- The `?nua-notes` flag sets a session cookie so subsequent navigation stays in review mode. Click "Exit" in the toolbar to drop back into CMS editing.
34
-
35
- ## What ships in v0.1
36
-
37
- | Feature | Status |
38
- | ------------------------------------------------------------------------------------------ | ------- |
39
- | Dev API at `/_nua/notes/*` (list, create, update, resolve, reopen, delete, apply) | ✓ |
40
- | Local JSON storage at `data/notes/pages/<slug>.json` (atomic writes, per-slug mutex) | ✓ |
41
- | Preact overlay mounted in a shadow DOM (zero CSS leakage either direction) | ✓ |
42
- | `?nua-notes` URL flag + cookie persistence + Exit toggle | ✓ |
43
- | Hide `@nuasite/cms` editor chrome in review mode (mode exclusivity) | ✓ |
44
- | **Pick mode** hover any `data-cms-id` element, click to comment | ✓ |
45
- | **Selection mode** — select text inside any element, leave a comment OR a range suggestion | ✓ |
46
- | Diff preview (− original / + suggested) on suggestion items in the sidebar | ✓ |
47
- | Anchor re-attachment after page reload falls back to whitespace-collapsed match | ✓ |
48
- | Stale badge when an anchor can't be found (source drifted) | ✓ |
49
- | **Apply flow** write the suggestion's replacement back to the source file | ✓ |
50
- | Resolve / reopen / delete actions on every item | ✓ |
51
- | Item author persisted in `localStorage` | ✓ |
52
- | Pre-built bundle (~16 kB gzipped) for npm consumers; source mode for monorepo dev | ✓ |
53
- | Sandbox / proxy mode (Cloudflare Worker forwarding) | Phase 5 |
54
- | Replies / threaded comments | Phase 5 |
55
- | Agency inbox view (cross-page list) | Phase 5 |
56
- | Theming via CSS variables, i18n, screenshot attachments | Phase 5 |
39
+ - `http://localhost:4321/?nua-notes` — review mode (client). Sidebar visible, CMS chrome hidden. Reviewers can comment or suggest. They cannot apply, resolve, or delete.
40
+ - `http://localhost:4321/?nua-notes&nua-agency` — review mode (agency). Same UI plus the destructive controls. The agency role is sticky: visit once, the cookie keeps you in agency mode for subsequent navigation.
41
+
42
+ The `?nua-notes` flag sets a session cookie so subsequent navigation stays in review mode. Click "Exit" in the toolbar to drop back into CMS editing (this also clears the agency cookie).
43
+
44
+ ## What ships in v0.2
45
+
46
+ | Feature | Status |
47
+ | ------------------------------------------------------------------------------------------------------- | ------- |
48
+ | Dev API at `/_nua/notes/*` (list, create, update, resolve, reopen, delete, **purge**, apply) | ✓ |
49
+ | Local JSON storage at `data/notes/pages/<slug>.json` (atomic writes, per-slug mutex) | ✓ |
50
+ | Preact overlay mounted in a shadow DOM (zero CSS leakage either direction) | ✓ |
51
+ | `?nua-notes` URL flag + cookie persistence + Exit toggle | ✓ |
52
+ | **`?nua-agency` URL flag** + sticky cookie + role indicator in the toolbar | ✓ |
53
+ | **Server-side role gating** — apply / delete / resolve / purge / update reject 403 without `x-nua-role` | ✓ |
54
+ | **Soft delete** agency Delete flips status to `deleted`, item stays on disk for the audit trail | ✓ |
55
+ | **Purge** hard delete from disk, agency only, used on already-deleted items | ✓ |
56
+ | **History trail** every mutation appends `{ at, action, role }` to `item.history`, visible to agency | ✓ |
57
+ | **Collapsed Deleted section** in the agency sidebar; clients never see it | ✓ |
58
+ | Hide `@nuasite/cms` editor chrome in review mode (mode exclusivity) | ✓ |
59
+ | **Pick mode** hover any `data-cms-id` element, click to comment | ✓ |
60
+ | **Selection mode** select text inside any element, leave a comment OR a range suggestion | ✓ |
61
+ | Diff preview (− original / + suggested) on suggestion items in the sidebar | ✓ |
62
+ | Anchor re-attachment after page reload falls back to whitespace-collapsed match | ✓ |
63
+ | Stale badge when an anchor can't be found (source drifted) | |
64
+ | **Apply flow** write the suggestion's replacement back to the source file (agency only) | ✓ |
65
+ | Resolve / reopen actions on every item (agency only) | ✓ |
66
+ | Item author persisted in `localStorage` | ✓ |
67
+ | Pre-built bundle (~18 kB gzipped) for npm consumers; source mode for monorepo dev | ✓ |
68
+ | Refreshed visual design — slate/zinc neutrals + muted blue accent, system-ui type, tighter spacing | ✓ |
69
+ | Sandbox / proxy mode (Cloudflare Worker forwarding) | Phase 5 |
70
+ | Replies / threaded comments | Phase 5 |
71
+ | Agency inbox view (cross-page list) | Phase 5 |
72
+ | Theming via CSS variables, i18n, screenshot attachments | Phase 5 |
57
73
 
58
74
  ## How it works
59
75
 
@@ -157,7 +173,27 @@ Both packages inject scripts into the same `astro:scripts/page.js` bundle. Mode
157
173
  - Without the URL flag: notes' loader returns early, mounts nothing, doesn't touch the DOM. CMS behaves byte-for-byte the same as before notes was installed.
158
174
  - With the URL flag: notes injects a stylesheet hiding CMS chrome and mounts its own UI inside a shadow DOM. Click handlers, focus, and z-index never collide because only one of the two UIs is visible at a time.
159
175
 
160
- A future version may negotiate via PostMessage so the two can coexist on screen (e.g. notes visible while CMS edit is active). For v0.1 the toggle is good enough.
176
+ A future version may negotiate via PostMessage so the two can coexist on screen (e.g. notes visible while CMS edit is active). For v0.2 the toggle is good enough.
177
+
178
+ ## Roles and permissions
179
+
180
+ Notes ships a two-role permission model designed to keep clients from accidentally rewriting source files or losing the audit trail.
181
+
182
+ | Action | Client | Agency |
183
+ | ---------------------------- | :----: | :----: |
184
+ | Create comment | ✓ | ✓ |
185
+ | Create suggestion | ✓ | ✓ |
186
+ | See own + others' open items | ✓ | ✓ |
187
+ | See resolved items | ✓ | ✓ |
188
+ | See deleted items / history | | ✓ |
189
+ | Resolve / Reopen | | ✓ |
190
+ | Apply suggestion to source | | ✓ |
191
+ | Delete (soft) | | ✓ |
192
+ | Purge (hard) | | ✓ |
193
+
194
+ The role is granted by visiting any page with `?nua-agency` once. The overlay sets a session cookie, and every API call sends `x-nua-role: agency` so the dev middleware can enforce the same gating server-side. Clicking **Exit** in the toolbar clears both the review-mode and the agency cookies.
195
+
196
+ **Trust model:** the role flag is unauthenticated. Anyone who knows the URL can claim agency. The point is to stop a non-technical client from accidentally clicking Apply, not to harden against an adversary. The dev server is local; real auth is out of scope for v0.2.
161
197
 
162
198
  ## Options
163
199
 
@@ -166,7 +202,8 @@ A future version may negotiate via PostMessage so the two can coexist on screen
166
202
  | `enabled` | `boolean` | `true` | Master switch. Set `false` to skip injection entirely. Ignored in production builds. |
167
203
  | `notesDir` | `string` | `'data/notes'` | Project-relative directory where note JSON files live. |
168
204
  | `urlFlag` | `string` | `'nua-notes'` | URL query parameter that activates review mode. |
169
- | `hideCmsInReviewMode` | `boolean` | `true` | Hide CMS editor chrome when notes mode is active. (Reserved for v0.2; v0.1 always hides.) |
205
+ | `agencyFlag` | `string` | `'nua-agency'` | URL query parameter that grants agency role + persists the sticky cookie. |
206
+ | `hideCmsInReviewMode` | `boolean` | `true` | Hide CMS editor chrome when notes mode is active. (Reserved for v0.3; v0.2 always hides.) |
170
207
  | `proxy` | `string?` | none | Forward `/_nua/notes/*` to this target. Mirrors the `proxy` option on `@nuasite/cms`. (Reserved for Phase 5.) |
171
208
 
172
209
  ## Hosting
@@ -177,18 +214,19 @@ When the project's CMS is configured to forward writes through the existing nuas
177
214
 
178
215
  ## API reference (dev)
179
216
 
180
- All endpoints are mounted under `/_nua/notes/`. Requests and responses are JSON.
181
-
182
- | Method | Path | Body | Response |
183
- | ------ | ------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------ |
184
- | `GET` | `/list?page=<page>` | — | `{ page, lastUpdated, items }` |
185
- | `GET` | `/inbox` | — | `{ pages: [...] }` (all pages) |
186
- | `POST` | `/create` | `{ page, type, targetCmsId, body, author, range?, ... }` | `{ item }` |
187
- | `POST` | `/update` | `{ page, id, patch }` | `{ item }` |
188
- | `POST` | `/resolve` | `{ page, id }` | `{ item }` (status → resolved) |
189
- | `POST` | `/reopen` | `{ page, id }` | `{ item }` (status → open) |
190
- | `POST` | `/delete` | `{ page, id }` | `{ ok: true }` |
191
- | `POST` | `/apply` | `{ page, id }` | `{ item, file, before, after }` (200) or `{ item, error, reason }` (409 stale) |
217
+ All endpoints are mounted under `/_nua/notes/`. Requests and responses are JSON. Routes marked **agency** require the `x-nua-role: agency` request header (the overlay sets it automatically when in agency mode); they return 403 otherwise.
218
+
219
+ | Method | Path | Role | Body | Response |
220
+ | ------ | ------------------- | ------ | -------------------------------------------------------- | ------------------------------------------------------------------------------ |
221
+ | `GET` | `/list?page=<page>` | any | — | `{ page, lastUpdated, items }` |
222
+ | `GET` | `/inbox` | any | — | `{ pages: [...] }` (all pages) |
223
+ | `POST` | `/create` | any | `{ page, type, targetCmsId, body, author, range?, ... }` | `{ item }` |
224
+ | `POST` | `/update` | agency | `{ page, id, patch }` | `{ item }` |
225
+ | `POST` | `/resolve` | agency | `{ page, id }` | `{ item }` (status → resolved) |
226
+ | `POST` | `/reopen` | agency | `{ page, id }` | `{ item }` (status → open) |
227
+ | `POST` | `/delete` | agency | `{ page, id }` | `{ item }` (status → deleted, **soft**, item stays on disk) |
228
+ | `POST` | `/purge` | agency | `{ page, id }` | `{ ok: true }` (hard, removes the item from disk) |
229
+ | `POST` | `/apply` | agency | `{ page, id }` | `{ item, file, before, after }` (200) or `{ item, error, reason }` (409 stale) |
192
230
 
193
231
  ## Architecture
194
232