@aiquants/daily-report 0.14.1 → 0.16.0

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.
Files changed (36) hide show
  1. package/README.md +30 -1
  2. package/dist/client.js +5 -5
  3. package/dist/client.js.map +1 -1
  4. package/dist/client.mjs +5 -5
  5. package/dist/client.mjs.map +1 -1
  6. package/dist/index.d.mts +14 -0
  7. package/dist/index.d.ts +14 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/server.d.mts +102 -18
  11. package/dist/server.d.ts +102 -18
  12. package/dist/server.js +10 -10
  13. package/dist/server.js.map +1 -1
  14. package/dist/server.mjs +10 -10
  15. package/dist/server.mjs.map +1 -1
  16. package/package.json +3 -3
  17. package/src/client/contexts/daily-report-action-context.spec.tsx +98 -1
  18. package/src/client/contexts/daily-report-action-context.tsx +22 -3
  19. package/src/client/hooks/use-daily-report.spec.ts +81 -0
  20. package/src/client/hooks/use-daily-report.ts +46 -3
  21. package/src/client/streaming/daily-report-ids-stream-client.spec.ts +69 -15
  22. package/src/client/streaming/daily-report-ids-stream-client.ts +10 -4
  23. package/src/client/streaming/daily-report-ids-stream-session.spec.ts +41 -0
  24. package/src/client/streaming/daily-report-ids-stream-session.ts +39 -0
  25. package/src/server/cache.spec.ts +64 -0
  26. package/src/server/cache.ts +17 -0
  27. package/src/server/handlers.ids-stream.spec.ts +119 -14
  28. package/src/server/handlers.ts +137 -34
  29. package/src/server/handlers.visibility.spec.ts +158 -0
  30. package/src/server/ports.ts +30 -3
  31. package/src/server/service.spec.ts +95 -0
  32. package/src/server/service.ts +54 -12
  33. package/src/server/test-helpers/handlers-config.ts +17 -1
  34. package/src/server/visibility.spec.ts +135 -0
  35. package/src/server/visibility.ts +107 -18
  36. package/src/shared/ids-stream.ts +14 -0
package/README.md CHANGED
@@ -144,8 +144,10 @@ createDailyReportServer({
144
144
  | Return value | Meaning |
145
145
  | --- | --- |
146
146
  | `undefined` / `null` | Unrestricted — every source type (the default when the port is not injected). |
147
- | `["legacy", "Internal"]` | Only those source types are visible. |
147
+ | `["legacy", "Internal"]` | Only those source types are visible (bodies **and** comments). |
148
148
  | `[]` | Nothing is visible (zero rows) — **not** the same as `null`. |
149
+ | `{ read: [...] }` | Same as returning the bare array — the comment dimension follows `read`. |
150
+ | `{ read: [...], comment: [...] }` | Bodies and comments restricted independently. See [Comment visibility](#comment-visibility). |
149
151
  | throws | Treated as `[]` (deny all). The failure is logged; an authorization-store outage never falls open. |
150
152
 
151
153
  - **Vocabulary**: the strings are `DailyReportHub.source_type` **values** — the `sourceType` of each entry you registered in `externalSources`, plus `"Internal"` which the package writes for reports it creates. They are *not* your authorization resource keys; mapping a resource key (e.g. `report_legacy`) onto a source type (e.g. `legacy`) is the consuming app's job. Read the canonical set at boot from `dailyReportServer.knownSourceTypes` and assert your mapping against it — an unknown token silently matches zero rows.
@@ -157,6 +159,33 @@ createDailyReportServer({
157
159
  - **Performance**: the port is called once per request on the critical path (cache keys incorporate the resolved set), so keep it fast — cache grants per session/user with a short TTL (≤ 60s). A live SSE connection re-resolves on its existing keep-alive tick (~60s) to bound how long a revoked grant keeps streaming; that call passes `reason: "refresh"` and reuses the connection's original `Request`, so a cache keyed on request identity **must** be bypassed when `reason === "refresh"` or the re-check silently returns the stale set.
158
160
  - **SSE latency**: because a live connection re-resolves periodically, a grant change (in either direction) takes effect for the stream within ~60s. Events dropped before a widening are not replayed; the next read (which re-resolves per request) restores them.
159
161
 
162
+ ### Comment visibility
163
+
164
+ Return `{ read, comment }` from the same port to restrict **reading and writing comments** independently of the report bodies — this is what connects a per-category comment permission (e.g. `daily_report_legacy_comment`) to actual access control.
165
+
166
+ ```ts
167
+ resolveVisibleSourceTypes: async (request, { reason }) => {
168
+ const grants = await yourAuthz.grantsFor(request, { skipCache: reason === "refresh" })
169
+ return {
170
+ read: grants.readableSourceTypes, // e.g. ["legacy", "Internal"]
171
+ comment: grants.commentableSourceTypes, // e.g. ["Internal"] — omit the key to follow `read`
172
+ }
173
+ },
174
+ ```
175
+
176
+ | `comment` | Meaning |
177
+ | --- | --- |
178
+ | omitted | Follows `read` — identical to returning a bare array. This is the default and the only spelling for "same as bodies". |
179
+ | `[]` | Comments are invisible and cannot be written, while the bodies stay readable. |
180
+ | `["Internal"]` | Only those source types' comments are visible/writable. Narrowed to `read ∩ comment` at construction, since comments only ever ship inside an already-read-filtered report. |
181
+
182
+ - **`null` is rejected by the type system** — a second spelling for "follow `read`" would make the dimension four-state and reintroduce exactly the unrestricted-vs-deny-all confusion the tri-state contract exists to prevent. A `null` that slips through at runtime fails **closed**.
183
+ - **What it covers**: `DailyReportDetail` carries comments in **two** structurally different fields — `commentItems` (the package's own comment table) and `comments` (legacy JSON supplied by an `externalSources` adapter). Both are gated. They are emptied, never omitted: the keys are required by the SSE schema, and dropping them would make a receiver discard the whole message.
184
+ - **Live events**: `comment-add` / `comment-delete` are judged on the comment dimension, and the report payload embedded in `report-create` / `report-update` / `report-publish` has its two comment arrays emptied per viewer at delivery time.
185
+ - **Your own comments are always visible and always deletable** (`commentItems` only — the legacy `comments` array carries no user identity, so it is all-or-nothing per source type). Hiding them would strand existing comments as undeletable the moment a grant is revoked, with no security gain.
186
+ - **Writing to external sources remains impossible regardless** — `addComment` rejects any non-`Internal` source type outright, so for external categories the comment dimension effectively controls *reading*.
187
+ - **Cache**: the dimension is folded into the cache-key digest, so revoking only the comment grant invalidates immediately. When `comment` follows `read` (the default) the digest is byte-identical to before, so existing deployments see no cache churn.
188
+
160
189
  ## Client wiring
161
190
 
162
191
  ```tsx