{"id":13568611,"url":"https://github.com/jahfer/clj-activitypub","last_synced_at":"2025-08-12T02:37:04.949Z","repository":{"id":64881748,"uuid":"571874126","full_name":"jahfer/clj-activitypub","owner":"jahfer","description":"An ActivityPub library for Clojure","archived":false,"fork":false,"pushed_at":"2023-12-20T00:29:02.000Z","size":101,"stargazers_count":32,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-07-02T12:08:11.493Z","etag":null,"topics":["activitypub","clojure","fediverse"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jahfer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-11-29T04:11:07.000Z","updated_at":"2025-03-25T15:07:53.000Z","dependencies_parsed_at":"2024-01-01T04:04:04.021Z","dependency_job_id":"35750749-2c52-45e8-88ca-740c8b582e17","html_url":"https://github.com/jahfer/clj-activitypub","commit_stats":{"total_commits":67,"total_committers":2,"mean_commits":33.5,"dds":0.05970149253731338,"last_synced_commit":"bdf9f57f815c4b6592c87ae21680f677f36b51f0"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/jahfer/clj-activitypub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahfer%2Fclj-activitypub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahfer%2Fclj-activitypub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahfer%2Fclj-activitypub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahfer%2Fclj-activitypub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jahfer","download_url":"https://codeload.github.com/jahfer/clj-activitypub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jahfer%2Fclj-activitypub/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264502425,"owners_count":23618605,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activitypub","clojure","fediverse"],"created_at":"2024-08-01T14:00:29.148Z","updated_at":"2025-08-12T02:37:04.916Z","avatar_url":"https://github.com/jahfer.png","language":"Clojure","funding_links":[],"categories":["Clojure"],"sub_categories":[],"readme":"# clj-activitypub\n\n[![Clojars Project](https://img.shields.io/clojars/v/com.jahfer/clj-activitypub.svg?include_prereleases)](https://clojars.org/com.jahfer/clj-activitypub)\n\n\u003e **Warning**\n\u003e This is very much a work-in-progress. Only a tiny bit of the ActivityPub spec is implemented, and it definitely does not conform to all of the nuances expected _yet_.\n\n`clj-activitypub` is a set of utilities that can be combined together to create a fully-functional ActivityPub server.\n\n## Documentation\nDocs are available at https://cljdoc.org/d/com.jahfer/clj-activitypub/\n\n## Libraries\n- `activitypub-core` — The base functionality for generating HTTP headers (i.e. `Signature`, `Digest`), building ActivityPub activities and objects, and sending requests to remote servers.\n- `activitypub-ring` — A Ring-specific implementation that builds on `activitypub-core`, providing default routes and handlers for making an ActivityPub-compliant server.\n\n## Examples\n\n```clj\n;; ActivityPub object handling\n(require '[clj-activitypub.core :as activitypub])\n;; Translate account handles into ActivityPub URL-based IDs\n(require '[clj-activitypub.webfinger :as webfinger])\n;; Build and perform network requests\n(require '[clj-activitypub.net :as activitypub-net])\n```\n\n### Reading remote data\n\n```clj\n;; Fetching user account on remote server\n\n(require '[clojure.pprint :refer [pprint]])\n\n;;; Use any ActivityPub account handle you like\n(def account-handle \"@jahfer@mastodon.social\")\n\n;;; Retrieve the account details from its home server\n(def account\n (-\u003e account-handle\n     (webfinger/parse-handle)\n     (webfinger/fetch-user-id!)\n     (activitypub-net/fetch-actor!)\n     (select-keys [:name :preferredUsername :summary])))\n\n;;; Examine what you got back!\n(pprint account) ;; =\u003e ({:name \"Jahfer\",\n                 ;;      :preferredUsername \"jahfer\",\n                 ;;      :summary \"\u003cp\u003eHello world!\u003c/p\u003e\"})\n```\n\n```clj\n;; Fetching a list of users from multiple servers\n(-\u003e \"https://mastodon.social/users/jahfer/followers\"\n    (activitypub-net/resolve!)\n    (count)) ;; =\u003e 80\n```\n\n### Pushing data to remote servers\n\nBefore POSTing data to a remote server, you'll want to create a local key/value pair in the `/keys` directory. You'll also need a corresponding HTTP endpoint to serve the actor data, which is used to verify the signature of the message by the remote server.\n\n```bash\n$ openssl genrsa -out keys/private.pem 2048\n$ openssl rsa -in keys/private.pem -outform PEM -pubout -out keys/public.pem\n```\n\n```clj\n;; Submitting a Create activity for an Object to remote server\n(require '[clj-http.client :as client])\n(require '[clojure.data.json :as json])\n(import java.net.URI)\n\n(def activity\n  (-\u003e\u003e {:id 2\n        :type :note\n        :cc \"https://mastodon.social/users/jahfer\"\n        :content \"\u003cp\u003eHello world!\u003c/p\u003e\"}\n       (activitypub/obj activity-config)\n       (activitypub/activity activity-config :create)))\n\n;;; Fetch the inboxes connected to the :cc addresses\n(let [targets (activitypub-net/delivery-targets! activity)]\n  (doseq [inbox targets]\n    ;;; At minimum, the Host is required to build the authentication headers\n    (let [request {:headers {\"Host\" (.getHost (URI. inbox))}\n                   :body (json/write-str activity)}]\n      ;;; Submit request to remote inboxes\n      (client/post\n        inbox\n        (assoc request\n               :headers (activitypub-net/auth-headers activity-config request)\n               :throw-exceptions false)))))\n```\n\n## Running tests\n\nThere are two libraries within this package: `activitypub-core` and `activitypub-ring`. In order to run tests, the following command must be run from inside either of those directories:\n\n```bash\n# clj-activitypub/activitypub_core\n$ clj -X:test\n```\n\n## References\n- https://www.w3.org/TR/activitypub/\n- https://www.w3.org/TR/activitystreams-core/\n- https://www.w3.org/ns/activitystreams#Public\n- https://www.w3.org/TR/activitystreams-vocabulary/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjahfer%2Fclj-activitypub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjahfer%2Fclj-activitypub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjahfer%2Fclj-activitypub/lists"}