sx-gitea Phase 6: activity — feed timelines, dashboard, durable notifications (TDD, 520/520)
lib/gitea/activity.sx: every forge action lands as a feed activity in an append-only persist log stream. Instrumentation is done IN the runtime — repo-create!/issue-create!/issue-comment!/pr-create!/pr-review!/pr-merge! are redefined around their originals, so SX callers and web handlers emit activity with zero call-site edits (failed mutations emit nothing). Timelines are lib/feed (APL) queries: global/repo/user, newest-first, visibility follows repo access (private-repo activity invisible to non-readers). Follows (user: or repo: targets) drive a dashboard of followed actors/repos minus one's own actions. Notifications ride lib/events durable delivery: activities after a cursor expand to (id recipient body) messages (comment -> author+ participants, review/merge -> PR author, open-issue -> assignees, never the actor), ev/deliver-messages runs the at-least-once digest flow, and delivered messages file into per-user kv inboxes; the cursor advance makes reruns no-ops. Web: /activity + /:owner/:name/activity pages, user-activity/dashboard/ follow/notifications/notify-run JSON API. gitea/all-routes now hoists every /api/* route ahead of the wildcard /:owner/:name patterns so later packs can add API endpoints without being shadowed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,10 @@
|
||||
; needs the owner (or org admin), delete and collaborator management need
|
||||
; "admin". 401 = no credentials, 403 = authenticated but not allowed.
|
||||
;
|
||||
; Later modules (wire, issues, ...) extend the app by appending a routes
|
||||
; pack to gitea/route-packs at load time; gitea/app serves them all.
|
||||
; Later modules (wire, issues, pr, activity, ...) extend the app by
|
||||
; appending a routes pack to gitea/route-packs at load time; gitea/app
|
||||
; serves them all, with every /api/* route hoisted ahead of the wildcard
|
||||
; /:owner/:name patterns so a pack can never be shadowed.
|
||||
;
|
||||
; Requires: lib/gitea/{repo,access}.sx, lib/dream/{types,router,middleware,
|
||||
; error,html,json,auth,api}.sx
|
||||
@@ -458,8 +460,6 @@
|
||||
(else (dream-not-found)))))))
|
||||
|
||||
; ── routes ───────────────────────────────────────────────────────────
|
||||
; /api/* is listed first so an owner segment can never shadow it (owner
|
||||
; names matching router words are rejected by gitea/valid-name? anyway).
|
||||
|
||||
(define
|
||||
gitea/routes
|
||||
@@ -500,16 +500,21 @@
|
||||
"/:owner/:name/raw/:ref/**"
|
||||
(fn (req) (gitea/w-raw forge req))))))
|
||||
|
||||
; extension point: wire/issues/... append their packs at load time
|
||||
; extension point: wire/issues/pr/activity/... append their packs at load
|
||||
(define gitea/route-packs (list gitea/routes))
|
||||
|
||||
; every /api/* route (from any pack) dispatches before the wildcard
|
||||
; /:owner/:name patterns, so later packs can add API endpoints freely
|
||||
(define
|
||||
gitea/all-routes
|
||||
(fn
|
||||
(forge)
|
||||
(reduce
|
||||
(fn (acc pack) (concat acc (pack forge)))
|
||||
(list)
|
||||
gitea/route-packs)))
|
||||
(let
|
||||
((rs (reduce (fn (acc pack) (concat acc (pack forge))) (list) gitea/route-packs)))
|
||||
(concat
|
||||
(filter (fn (r) (starts-with? (dream-route-path r) "/api/")) rs)
|
||||
(filter
|
||||
(fn (r) (not (starts-with? (dream-route-path r) "/api/")))
|
||||
rs)))))
|
||||
|
||||
(define gitea/app (fn (forge) (dream-make-app (gitea/all-routes forge))))
|
||||
|
||||
Reference in New Issue
Block a user