···2020 let doc =
2121 "Key ID (default: <actor_uri>#main-key). Usually the actor's publicKey.id."
2222 in
2323- Arg.(
2424- value & opt (some string) None & info [ "key-id"; "K" ] ~docv:"URI" ~doc)
2323+ Arg.(value & opt (some string) None & info [ "key-id"; "K" ] ~docv:"URI" ~doc)
25242625let profile_arg =
2726 let doc =
···6766 | None -> Apub_auth_session.profile_name_of_actor_uri actor_uri
6867 in
6968 (* Create and save session *)
7070- let session =
7171- Apub_auth_session.create ~actor_uri ~key_id ~private_key_pem
7272- in
6969+ let session = Apub_auth_session.create ~actor_uri ~key_id ~private_key_pem in
7370 Apub_auth_session.save fs ~app_name ~profile:profile_name session;
7471 (* Set as current profile if first setup or explicitly requested *)
7572 let profiles = Apub_auth_session.list_profiles fs ~app_name in
···9188 `Pre
9289 " apub auth setup https://example.com/users/alice -k \
9390 ~/.config/apub/key.pem";
9494- `Pre
9595- " apub auth setup https://mastodon.social/users/bob --profile work";
9191+ `Pre " apub auth setup https://mastodon.social/users/bob --profile work";
9692 ]
9793 in
9894 let info = Cmd.info "setup" ~doc ~man in
···10197 setup_action ~app_name ~actor_uri ~key_file ~key_id ~profile env
10298 in
10399 Cmd.v info
104104- Term.(const setup' $ actor_uri_arg $ key_file_arg $ key_id_arg $ profile_arg)
100100+ Term.(
101101+ const setup' $ actor_uri_arg $ key_file_arg $ key_id_arg $ profile_arg)
105102106103(* Login command - OAuth login with Mastodon instance *)
107104···113110 Crypto_rng_unix.use_default ();
114111 let fs = env#fs in
115112 (* Extract instance from account *)
116116- let instance = match Apub_mastodon_oauth.instance_of_account account with
113113+ let instance =
114114+ match Apub_mastodon_oauth.instance_of_account account with
117115 | Some i -> i
118116 | None ->
119117 Fmt.epr "Error: Invalid account format. Use user@instance.social@.";
···126124 let requests = Requests.v ~sw ~timeout:timeout_config env in
127125 (* Step 1: Register OAuth app *)
128126 Fmt.pr "Registering OAuth app...@.";
129129- let app = match Apub_mastodon_oauth.register_app requests ~instance with
127127+ let app =
128128+ match Apub_mastodon_oauth.register_app requests ~instance with
130129 | Ok app -> app
131130 | Error msg ->
132131 Fmt.epr "Error: %s@." msg;
133132 exit 1
134133 in
135134 (* Step 2: Generate PKCE *)
136136- let (code_verifier, code_challenge) = Apub_mastodon_oauth.Pkce.generate () in
135135+ let code_verifier, code_challenge = Apub_mastodon_oauth.Pkce.generate () in
137136 (* Step 3: Display authorization URL *)
138138- let auth_url = Apub_mastodon_oauth.authorization_url
139139- ~instance
140140- ~client_id:app.client_id
141141- ~code_challenge
137137+ let auth_url =
138138+ Apub_mastodon_oauth.authorization_url ~instance ~client_id:app.client_id
139139+ ~code_challenge
142140 in
143141 Fmt.pr "@.Please visit this URL to authorize:@.";
144142 Fmt.pr "@. %s@.@." auth_url;
···151149 end;
152150 (* Step 4: Exchange code for token *)
153151 Fmt.pr "Exchanging authorization code...@.";
154154- let token = match Apub_mastodon_oauth.exchange_code requests
155155- ~instance
156156- ~client_id:app.client_id
157157- ~client_secret:app.client_secret
158158- ~code
159159- ~code_verifier
160160- with
152152+ let token =
153153+ match
154154+ Apub_mastodon_oauth.exchange_code requests ~instance
155155+ ~client_id:app.client_id ~client_secret:app.client_secret ~code
156156+ ~code_verifier
157157+ with
161158 | Ok t -> t
162159 | Error msg ->
163160 Fmt.epr "Error: %s@." msg;
···165162 in
166163 (* Step 5: Verify credentials *)
167164 Fmt.pr "Verifying credentials...@.";
168168- let account_info = match Apub_mastodon_oauth.verify_credentials requests
169169- ~instance
170170- ~access_token:token.access_token
171171- with
165165+ let account_info =
166166+ match
167167+ Apub_mastodon_oauth.verify_credentials requests ~instance
168168+ ~access_token:token.access_token
169169+ with
172170 | Ok a -> a
173171 | Error msg ->
174172 Fmt.epr "Error: %s@." msg;
175173 exit 1
176174 in
177175 (* Step 6: Save session *)
178178- let actor_uri = Apub_mastodon_oauth.actor_uri_of_account_url account_info.url in
179179- let profile_name = match profile with
176176+ let actor_uri =
177177+ Apub_mastodon_oauth.actor_uri_of_account_url account_info.url
178178+ in
179179+ let profile_name =
180180+ match profile with
180181 | Some p -> p
181182 | None -> account_info.acct ^ "@" ^ instance
182183 in
183183- let session = Apub_auth_session.create_oauth
184184- ~actor_uri
185185- ~instance
186186- ~access_token:token.access_token
187187- ~client_id:app.client_id
188188- ~client_secret:app.client_secret
184184+ let session =
185185+ Apub_auth_session.create_oauth ~actor_uri ~instance
186186+ ~access_token:token.access_token ~client_id:app.client_id
187187+ ~client_secret:app.client_secret
189188 in
190189 Apub_auth_session.save fs ~app_name ~profile:profile_name session;
191190 (* Set as current profile if first setup or explicitly requested *)
···216215 in
217216 let info = Cmd.info "login" ~doc ~man in
218217 let login' account profile =
219219- Eio_main.run @@ fun env ->
220220- login_action ~app_name ~account ~profile env
218218+ Eio_main.run @@ fun env -> login_action ~app_name ~account ~profile env
221219 in
222220 Cmd.v info Term.(const login' $ account_arg $ profile_arg)
223221···263261 Fmt.pr "Profile '%s':@." profile;
264262 Fmt.pr " Actor: %s@." session.actor_uri;
265263 (* Show signature auth if present *)
266266- Option.iter (fun key_id ->
267267- Fmt.pr " Key ID: %s@." key_id
268268- ) session.key_id;
264264+ Option.iter (fun key_id -> Fmt.pr " Key ID: %s@." key_id) session.key_id;
269265 (* Show OAuth auth if present *)
270270- Option.iter (fun instance ->
271271- Fmt.pr " OAuth Instance: %s@." instance
272272- ) session.oauth_instance;
266266+ Option.iter
267267+ (fun instance -> Fmt.pr " OAuth Instance: %s@." instance)
268268+ session.oauth_instance;
273269 (match session.oauth_access_token with
274274- | Some _ -> Fmt.pr " OAuth Token: Configured@."
275275- | None -> ());
270270+ | Some _ -> Fmt.pr " OAuth Token: Configured@."
271271+ | None -> ());
276272 (* Show auth type summary *)
277277- let auth_types = List.filter_map (fun x -> x) [
278278- (if Apub_auth_session.has_signature session then Some "HTTP Signatures" else None);
279279- (if Apub_auth_session.has_oauth session then Some "OAuth" else None);
280280- ] in
273273+ let auth_types =
274274+ List.filter_map
275275+ (fun x -> x)
276276+ [
277277+ (if Apub_auth_session.has_signature session then
278278+ Some "HTTP Signatures"
279279+ else None);
280280+ (if Apub_auth_session.has_oauth session then Some "OAuth" else None);
281281+ ]
282282+ in
281283 if auth_types <> [] then
282284 Fmt.pr " Auth: %s@." (String.concat ", " auth_types);
283285 Fmt.pr " Created: %s@." session.created_at
···394396 match profile with
395397 | Some p -> Printf.sprintf " (profile: %s)" p
396398 | None ->
397397- let current =
398398- Apub_auth_session.get_current_profile fs ~app_name
399399- in
399399+ let current = Apub_auth_session.get_current_profile fs ~app_name in
400400 Printf.sprintf " (profile: %s)" current
401401 in
402402 Fmt.epr "Not configured%s. Use '%s auth setup' first.@." profile_msg
+9-10
lib/auth/apub_auth_cmd.mli
···2424 {2 Usage}
25252626 {[
2727- (* Add auth commands to your CLI *)
2828- let cmds =
2929- [
3030- Apub_auth_cmd.auth_cmd ~app_name:"apub" ();
3131- (* ... other commands ... *)
3232- ]
2727+ (* Add auth commands to your CLI *)
2828+ let cmds =
2929+ [
3030+ Apub_auth_cmd.auth_cmd ~app_name:"apub" (); (* ... other commands ... *)
3131+ ]
3332 ]} *)
34333534(** {1 Command Groups} *)
36353736val auth_cmd : app_name:string -> unit -> unit Cmdliner.Cmd.t
3838-(** [auth_cmd ~app_name ()] creates the auth command group with all
3939- subcommands. *)
3737+(** [auth_cmd ~app_name ()] creates the auth command group with all subcommands.
3838+*)
40394140val setup_cmd : app_name:string -> unit -> unit Cmdliner.Cmd.t
4241(** [setup_cmd ~app_name ()] creates the setup command for importing keys. *)
···5857 (Eio.Fs.dir_ty Eio.Path.t -> Apub_auth_session.t -> 'a) ->
5958 < fs : Eio.Fs.dir_ty Eio.Path.t ; .. > ->
6059 'a
6161-(** [with_session ~app_name ?profile f env] loads the session and calls [f]
6262- with it, or exits with an error if no session is found. *)
6060+(** [with_session ~app_name ?profile f env] loads the session and calls [f] with
6161+ it, or exits with an error if no session is found. *)
63626463(** {1 Cmdliner Arguments} *)
6564
+45-26
lib/auth/apub_auth_session.ml
···18181919let jsont =
2020 Json.Codec.Object.map ~kind:"Session"
2121- (fun actor_uri key_id private_key_pem oauth_instance oauth_access_token
2222- oauth_client_id oauth_client_secret created_at ->
2323- { actor_uri; key_id; private_key_pem; oauth_instance; oauth_access_token;
2424- oauth_client_id; oauth_client_secret; created_at })
2525- |> Json.Codec.Object.member "actor_uri" Json.Codec.string ~enc:(fun s -> s.actor_uri)
2626- |> Json.Codec.Object.opt_member "key_id" Json.Codec.string ~enc:(fun s -> s.key_id)
2121+ (fun
2222+ actor_uri
2323+ key_id
2424+ private_key_pem
2525+ oauth_instance
2626+ oauth_access_token
2727+ oauth_client_id
2828+ oauth_client_secret
2929+ created_at
3030+ ->
3131+ {
3232+ actor_uri;
3333+ key_id;
3434+ private_key_pem;
3535+ oauth_instance;
3636+ oauth_access_token;
3737+ oauth_client_id;
3838+ oauth_client_secret;
3939+ created_at;
4040+ })
4141+ |> Json.Codec.Object.member "actor_uri" Json.Codec.string ~enc:(fun s ->
4242+ s.actor_uri)
4343+ |> Json.Codec.Object.opt_member "key_id" Json.Codec.string ~enc:(fun s ->
4444+ s.key_id)
2745 |> Json.Codec.Object.opt_member "private_key_pem" Json.Codec.string
2846 ~enc:(fun s -> s.private_key_pem)
2947 |> Json.Codec.Object.opt_member "oauth_instance" Json.Codec.string
···3452 ~enc:(fun s -> s.oauth_client_id)
3553 |> Json.Codec.Object.opt_member "oauth_client_secret" Json.Codec.string
3654 ~enc:(fun s -> s.oauth_client_secret)
3737- |> Json.Codec.Object.member "created_at" Json.Codec.string ~enc:(fun s -> s.created_at)
5555+ |> Json.Codec.Object.member "created_at" Json.Codec.string ~enc:(fun s ->
5656+ s.created_at)
3857 |> Json.Codec.Object.seal
39584059(* App config stores the current profile *)
···4463 Json.Codec.Object.map ~kind:"AppConfig" (fun current_profile ->
4564 { current_profile })
4665 |> Json.Codec.Object.member "current_profile" Json.Codec.string ~enc:(fun c ->
4747- c.current_profile)
6666+ c.current_profile)
4867 |> Json.Codec.Object.seal
49685069let default_profile = "default"
···8610587106let load_app_config fs ~app_name =
88107 let path = app_config_file fs ~app_name in
8989- try
9090- Eio.Path.load path
9191- |> Json.of_string app_config_jsont
9292- |> Result.to_option
108108+ try Eio.Path.load path |> Json.of_string app_config_jsont |> Result.to_option
93109 with Eio.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> None
9411095111let save_app_config fs ~app_name config =
···113129 try
114130 Eio.Path.read_dir profiles
115131 |> List.filter (fun name ->
116116- (* Check if it's a directory with a session.json *)
117117- let dir = Eio.Path.(profiles / name) in
118118- let session = Eio.Path.(dir / "session.json") in
119119- try
120120- ignore (Eio.Path.load session);
121121- true
122122- with _ -> false)
132132+ (* Check if it's a directory with a session.json *)
133133+ let dir = Eio.Path.(profiles / name) in
134134+ let session = Eio.Path.(dir / "session.json") in
135135+ try
136136+ ignore (Eio.Path.load session);
137137+ true
138138+ with _ -> false)
123139 |> List.sort String.compare
124140 with Eio.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> []
125141···137153 Some current
138154 in
139155 let path = session_file fs ~app_name ?profile () in
140140- try
141141- Eio.Path.load path |> Json.of_string jsont |> Result.to_option
156156+ try Eio.Path.load path |> Json.of_string jsont |> Result.to_option
142157 with Eio.Io (Eio.Fs.E (Eio.Fs.Not_found _), _) -> None
143158144159let save fs ~app_name ?profile session =
···164179let pp ppf session =
165180 Fmt.pf ppf "@[<v>Actor: %s@," session.actor_uri;
166181 Option.iter (fun k -> Fmt.pf ppf "Key ID: %s@," k) session.key_id;
167167- Option.iter (fun i -> Fmt.pf ppf "OAuth Instance: %s@," i) session.oauth_instance;
182182+ Option.iter
183183+ (fun i -> Fmt.pf ppf "OAuth Instance: %s@," i)
184184+ session.oauth_instance;
168185 (match session.oauth_access_token with
169169- | Some _ -> Fmt.pf ppf "OAuth: Configured@,"
170170- | None -> ());
186186+ | Some _ -> Fmt.pf ppf "OAuth: Configured@,"
187187+ | None -> ());
171188 Fmt.pf ppf "Created: %s@]" session.created_at
172189173190(* Create a signature-based session from components *)
···198215199216(* Merge OAuth credentials into an existing session (for hybrid auth) *)
200217let add_oauth session ~instance ~access_token ~client_id ~client_secret =
201201- { session with
218218+ {
219219+ session with
202220 oauth_instance = Some instance;
203221 oauth_access_token = Some access_token;
204222 oauth_client_id = Some client_id;
···211229212230(* Check if session has OAuth auth *)
213231let has_oauth session =
214214- Option.is_some session.oauth_access_token && Option.is_some session.oauth_instance
232232+ Option.is_some session.oauth_access_token
233233+ && Option.is_some session.oauth_instance
215234216235(* Extract a profile name from an actor URI *)
217236let profile_name_of_actor_uri uri =
+4-3
lib/auth/apub_auth_session.mli
···9393 client_id:string ->
9494 client_secret:string ->
9595 t
9696-(** [add_oauth session ~instance ~access_token ~client_id ~client_secret]
9797- adds OAuth credentials to an existing session for hybrid auth. *)
9696+(** [add_oauth session ~instance ~access_token ~client_id ~client_secret] adds
9797+ OAuth credentials to an existing session for hybrid auth. *)
98989999val has_signature : t -> bool
100100(** [has_signature session] returns true if the session has HTTP signature
···106106107107val profile_name_of_actor_uri : string -> string
108108(** [profile_name_of_actor_uri uri] extracts a profile name from an actor URI.
109109- For example, [https://example.com/users/alice] becomes [alice@example.com]. *)
109109+ For example, [https://example.com/users/alice] becomes [alice@example.com].
110110+*)
110111111112(** {1 Profile Management} *)
112113
+63-36
lib/auth/apub_mastodon_api.ml
···1414 | Private -> "private"
1515 | Direct -> "direct"
16161717-(** Status response *)
1817type status = {
1918 id : string;
2019 uri : string;
···2322 created_at : string;
2423 visibility : string;
2524}
2525+(** Status response *)
26262727let status_jsont =
2828 Json.Codec.Object.map ~kind:"MastodonStatus"
···3131 |> Json.Codec.Object.member "id" Json.Codec.string ~enc:(fun s -> s.id)
3232 |> Json.Codec.Object.member "uri" Json.Codec.string ~enc:(fun s -> s.uri)
3333 |> Json.Codec.Object.opt_member "url" Json.Codec.string ~enc:(fun s -> s.url)
3434- |> Json.Codec.Object.member "content" Json.Codec.string ~enc:(fun s -> s.content)
3535- |> Json.Codec.Object.member "created_at" Json.Codec.string ~enc:(fun s -> s.created_at)
3636- |> Json.Codec.Object.member "visibility" Json.Codec.string ~enc:(fun s -> s.visibility)
3434+ |> Json.Codec.Object.member "content" Json.Codec.string ~enc:(fun s ->
3535+ s.content)
3636+ |> Json.Codec.Object.member "created_at" Json.Codec.string ~enc:(fun s ->
3737+ s.created_at)
3838+ |> Json.Codec.Object.member "visibility" Json.Codec.string ~enc:(fun s ->
3939+ s.visibility)
3740 |> Json.Codec.Object.seal
38413939-(** Relationship response (for follow/unfollow) *)
4042type relationship = {
4143 id : string;
4244 following : bool;
···4547 muting : bool;
4648 requested : bool;
4749}
5050+(** Relationship response (for follow/unfollow) *)
48514952let relationship_jsont =
5053 Json.Codec.Object.map ~kind:"MastodonRelationship"
5154 (fun id following followed_by blocking muting requested ->
5255 { id; following; followed_by; blocking; muting; requested })
5356 |> Json.Codec.Object.member "id" Json.Codec.string ~enc:(fun r -> r.id)
5454- |> Json.Codec.Object.member "following" Json.Codec.bool ~enc:(fun r -> r.following)
5555- |> Json.Codec.Object.member "followed_by" Json.Codec.bool ~enc:(fun r -> r.followed_by)
5656- |> Json.Codec.Object.member "blocking" Json.Codec.bool ~enc:(fun r -> r.blocking)
5757+ |> Json.Codec.Object.member "following" Json.Codec.bool ~enc:(fun r ->
5858+ r.following)
5959+ |> Json.Codec.Object.member "followed_by" Json.Codec.bool ~enc:(fun r ->
6060+ r.followed_by)
6161+ |> Json.Codec.Object.member "blocking" Json.Codec.bool ~enc:(fun r ->
6262+ r.blocking)
5763 |> Json.Codec.Object.member "muting" Json.Codec.bool ~enc:(fun r -> r.muting)
5858- |> Json.Codec.Object.member "requested" Json.Codec.bool ~enc:(fun r -> r.requested)
6464+ |> Json.Codec.Object.member "requested" Json.Codec.bool ~enc:(fun r ->
6565+ r.requested)
5966 |> Json.Codec.Object.seal
60676168(** Helper to create authenticated headers *)
6262-let auth_headers token =
6363- Requests.Headers.empty
6464- |> Requests.Headers.bearer token
6969+let auth_headers token = Requests.Headers.empty |> Requests.Headers.bearer token
65706671(** Check response and return error if not successful *)
6772let check_response resp =
6873 let status = Requests.Response.status_code resp in
6969- if status >= 200 && status < 300 then
7070- Ok ()
7474+ if status >= 200 && status < 300 then Ok ()
7175 else
7276 let body = Requests.Response.text resp in
7377 Error (Printf.sprintf "HTTP %d: %s" status body)
74787579(** Post a new status *)
7676-let post_status requests ~instance ~token ~content
7777- ?(visibility = Public) ?in_reply_to_id ?sensitive ?spoiler_text () =
8080+let post_status requests ~instance ~token ~content ?(visibility = Public)
8181+ ?in_reply_to_id ?sensitive ?spoiler_text () =
7882 let url = Printf.sprintf "https://%s/api/v1/statuses" instance in
7983 let headers = auth_headers token in
8080- let params = [
8181- ("status", content);
8282- ("visibility", string_of_visibility visibility);
8383- ] in
8484- let params = match in_reply_to_id with
8484+ let params =
8585+ [ ("status", content); ("visibility", string_of_visibility visibility) ]
8686+ in
8787+ let params =
8888+ match in_reply_to_id with
8589 | Some id -> ("in_reply_to_id", id) :: params
8690 | None -> params
8791 in
8888- let params = match sensitive with
9292+ let params =
9393+ match sensitive with
8994 | Some true -> ("sensitive", "true") :: params
9095 | _ -> params
9196 in
9292- let params = match spoiler_text with
9797+ let params =
9898+ match spoiler_text with
9399 | Some text -> ("spoiler_text", text) :: params
94100 | None -> params
95101 in
···101107102108(** Favourite (like) a status *)
103109let favourite requests ~instance ~token ~status_id =
104104- let url = Printf.sprintf "https://%s/api/v1/statuses/%s/favourite" instance status_id in
110110+ let url =
111111+ Printf.sprintf "https://%s/api/v1/statuses/%s/favourite" instance status_id
112112+ in
105113 let headers = auth_headers token in
106114 let resp = Requests.post requests ~headers url in
107115 match check_response resp with
···110118111119(** Unfavourite a status *)
112120let unfavourite requests ~instance ~token ~status_id =
113113- let url = Printf.sprintf "https://%s/api/v1/statuses/%s/unfavourite" instance status_id in
121121+ let url =
122122+ Printf.sprintf "https://%s/api/v1/statuses/%s/unfavourite" instance
123123+ status_id
124124+ in
114125 let headers = auth_headers token in
115126 let resp = Requests.post requests ~headers url in
116127 match check_response resp with
···119130120131(** Reblog (boost) a status *)
121132let reblog requests ~instance ~token ~status_id =
122122- let url = Printf.sprintf "https://%s/api/v1/statuses/%s/reblog" instance status_id in
133133+ let url =
134134+ Printf.sprintf "https://%s/api/v1/statuses/%s/reblog" instance status_id
135135+ in
123136 let headers = auth_headers token in
124137 let resp = Requests.post requests ~headers url in
125138 match check_response resp with
···128141129142(** Unreblog a status *)
130143let unreblog requests ~instance ~token ~status_id =
131131- let url = Printf.sprintf "https://%s/api/v1/statuses/%s/unreblog" instance status_id in
144144+ let url =
145145+ Printf.sprintf "https://%s/api/v1/statuses/%s/unreblog" instance status_id
146146+ in
132147 let headers = auth_headers token in
133148 let resp = Requests.post requests ~headers url in
134149 match check_response resp with
···137152138153(** Follow an account by ID *)
139154let follow requests ~instance ~token ~account_id =
140140- let url = Printf.sprintf "https://%s/api/v1/accounts/%s/follow" instance account_id in
155155+ let url =
156156+ Printf.sprintf "https://%s/api/v1/accounts/%s/follow" instance account_id
157157+ in
141158 let headers = auth_headers token in
142159 let resp = Requests.post requests ~headers url in
143160 match check_response resp with
···146163147164(** Unfollow an account by ID *)
148165let unfollow requests ~instance ~token ~account_id =
149149- let url = Printf.sprintf "https://%s/api/v1/accounts/%s/unfollow" instance account_id in
166166+ let url =
167167+ Printf.sprintf "https://%s/api/v1/accounts/%s/unfollow" instance account_id
168168+ in
150169 let headers = auth_headers token in
151170 let resp = Requests.post requests ~headers url in
152171 match check_response resp with
···155174156175(** Look up an account by webfinger address (user@domain) *)
157176let lookup_account requests ~instance ~token ~acct =
158158- let url = Printf.sprintf "https://%s/api/v1/accounts/lookup?acct=%s"
159159- instance (Uri.pct_encode acct) in
177177+ let url =
178178+ Printf.sprintf "https://%s/api/v1/accounts/lookup?acct=%s" instance
179179+ (Uri.pct_encode acct)
180180+ in
160181 let headers = auth_headers token in
161182 let resp = Requests.get requests ~headers url in
162183 match check_response resp with
···165186166187(** Search for accounts *)
167188let search_accounts requests ~instance ~token ~query ?(limit = 10) () =
168168- let url = Printf.sprintf "https://%s/api/v1/accounts/search?q=%s&limit=%d"
169169- instance (Uri.pct_encode query) limit in
189189+ let url =
190190+ Printf.sprintf "https://%s/api/v1/accounts/search?q=%s&limit=%d" instance
191191+ (Uri.pct_encode query) limit
192192+ in
170193 let headers = auth_headers token in
171194 let resp = Requests.get requests ~headers url in
172195 match check_response resp with
173196 | Error e -> Error e
174174- | Ok () -> Ok (Requests.Response.jsonv (Json.Codec.list Apub_mastodon_oauth.account_jsont) resp)
197197+ | Ok () ->
198198+ Ok
199199+ (Requests.Response.jsonv
200200+ (Json.Codec.list Apub_mastodon_oauth.account_jsont)
201201+ resp)
175202176203(** Get a status by ID *)
177204let get_status requests ~instance ~token ~status_id =
···189216 let resp = Requests.delete requests ~headers url in
190217 check_response resp
191218192192-(** Extract status ID from a Mastodon URL like https://instance/users/name/statuses/123
193193- or https://instance/@name/123 *)
219219+(** Extract status ID from a Mastodon URL like
220220+ https://instance/users/name/statuses/123 or https://instance/@name/123 *)
194221let status_id_of_url url =
195222 let uri = Uri.of_string url in
196223 let path = Uri.path uri in
+60-42
lib/auth/apub_mastodon_oauth.ml
···1616(** Redirect URI for out-of-band CLI authorization *)
1717let redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
18181919-(** App registration response *)
2019type app = {
2120 client_id : string;
2221 client_secret : string;
2322 vapid_key : string option;
2423}
2424+(** App registration response *)
25252626let app_jsont =
2727 Json.Codec.Object.map ~kind:"MastodonApp"
2828 (fun client_id client_secret vapid_key ->
2929 { client_id; client_secret; vapid_key })
3030- |> Json.Codec.Object.member "client_id" Json.Codec.string ~enc:(fun a -> a.client_id)
3131- |> Json.Codec.Object.member "client_secret" Json.Codec.string ~enc:(fun a -> a.client_secret)
3232- |> Json.Codec.Object.opt_member "vapid_key" Json.Codec.string ~enc:(fun a -> a.vapid_key)
3030+ |> Json.Codec.Object.member "client_id" Json.Codec.string ~enc:(fun a ->
3131+ a.client_id)
3232+ |> Json.Codec.Object.member "client_secret" Json.Codec.string ~enc:(fun a ->
3333+ a.client_secret)
3434+ |> Json.Codec.Object.opt_member "vapid_key" Json.Codec.string ~enc:(fun a ->
3535+ a.vapid_key)
3336 |> Json.Codec.Object.seal
34373535-(** Token response *)
3638type token = {
3739 access_token : string;
3840 token_type : string;
3941 scope : string;
4042 created_at : int;
4143}
4444+(** Token response *)
42454346let token_jsont =
4447 Json.Codec.Object.map ~kind:"MastodonToken"
4548 (fun access_token token_type scope created_at ->
4649 { access_token; token_type; scope; created_at })
4747- |> Json.Codec.Object.member "access_token" Json.Codec.string ~enc:(fun t -> t.access_token)
4848- |> Json.Codec.Object.member "token_type" Json.Codec.string ~enc:(fun t -> t.token_type)
5050+ |> Json.Codec.Object.member "access_token" Json.Codec.string ~enc:(fun t ->
5151+ t.access_token)
5252+ |> Json.Codec.Object.member "token_type" Json.Codec.string ~enc:(fun t ->
5353+ t.token_type)
4954 |> Json.Codec.Object.member "scope" Json.Codec.string ~enc:(fun t -> t.scope)
5050- |> Json.Codec.Object.member "created_at" Json.Codec.int ~enc:(fun t -> t.created_at)
5555+ |> Json.Codec.Object.member "created_at" Json.Codec.int ~enc:(fun t ->
5656+ t.created_at)
5157 |> Json.Codec.Object.seal
52585353-(** Account (verify_credentials response) *)
5459type account = {
5560 id : string;
5661 username : string;
···5863 display_name : string option;
5964 url : string;
6065}
6666+(** Account (verify_credentials response) *)
61676268let account_jsont =
6369 Json.Codec.Object.map ~kind:"MastodonAccount"
6470 (fun id username acct display_name url ->
6571 { id; username; acct; display_name; url })
6672 |> Json.Codec.Object.member "id" Json.Codec.string ~enc:(fun a -> a.id)
6767- |> Json.Codec.Object.member "username" Json.Codec.string ~enc:(fun a -> a.username)
7373+ |> Json.Codec.Object.member "username" Json.Codec.string ~enc:(fun a ->
7474+ a.username)
6875 |> Json.Codec.Object.member "acct" Json.Codec.string ~enc:(fun a -> a.acct)
6969- |> Json.Codec.Object.opt_member "display_name" Json.Codec.string ~enc:(fun a -> a.display_name)
7676+ |> Json.Codec.Object.opt_member "display_name" Json.Codec.string
7777+ ~enc:(fun a -> a.display_name)
7078 |> Json.Codec.Object.member "url" Json.Codec.string ~enc:(fun a -> a.url)
7179 |> Json.Codec.Object.seal
7280···94102(** Extract instance domain from account handle (user@instance.social) *)
95103let instance_of_account account =
96104 match String.split_on_char '@' account with
9797- | [_user; instance] -> Some instance
105105+ | [ _user; instance ] -> Some instance
98106 | _ -> None
99107100108(** Register a new OAuth app with the instance *)
101109let register_app requests ~instance =
102110 let url = Printf.sprintf "https://%s/api/v1/apps" instance in
103103- let params = [
104104- ("client_name", client_name);
105105- ("redirect_uris", redirect_uri);
106106- ("scopes", scopes);
107107- ("website", "https://github.com/avsm/apub");
108108- ] in
111111+ let params =
112112+ [
113113+ ("client_name", client_name);
114114+ ("redirect_uris", redirect_uri);
115115+ ("scopes", scopes);
116116+ ("website", "https://github.com/avsm/apub");
117117+ ]
118118+ in
109119 let body = Requests.Body.form params in
110120 let resp = Requests.post requests ~body url in
111121 let status = Requests.Response.status_code resp in
···118128(** Build the authorization URL for the user to visit *)
119129let authorization_url ~instance ~client_id ~code_challenge =
120130 let base = Printf.sprintf "https://%s/oauth/authorize" instance in
121121- let params = [
122122- ("response_type", "code");
123123- ("client_id", client_id);
124124- ("redirect_uri", redirect_uri);
125125- ("scope", scopes);
126126- ("code_challenge", code_challenge);
127127- ("code_challenge_method", "S256");
128128- ] in
129129- let query = String.concat "&" (List.map (fun (k, v) ->
130130- k ^ "=" ^ Uri.pct_encode v
131131- ) params) in
131131+ let params =
132132+ [
133133+ ("response_type", "code");
134134+ ("client_id", client_id);
135135+ ("redirect_uri", redirect_uri);
136136+ ("scope", scopes);
137137+ ("code_challenge", code_challenge);
138138+ ("code_challenge_method", "S256");
139139+ ]
140140+ in
141141+ let query =
142142+ String.concat "&"
143143+ (List.map (fun (k, v) -> k ^ "=" ^ Uri.pct_encode v) params)
144144+ in
132145 base ^ "?" ^ query
133146134147(** Exchange authorization code for access token *)
135135-let exchange_code requests ~instance ~client_id ~client_secret ~code ~code_verifier =
148148+let exchange_code requests ~instance ~client_id ~client_secret ~code
149149+ ~code_verifier =
136150 let url = Printf.sprintf "https://%s/oauth/token" instance in
137137- let params = [
138138- ("grant_type", "authorization_code");
139139- ("code", code);
140140- ("client_id", client_id);
141141- ("client_secret", client_secret);
142142- ("redirect_uri", redirect_uri);
143143- ("code_verifier", code_verifier);
144144- ] in
151151+ let params =
152152+ [
153153+ ("grant_type", "authorization_code");
154154+ ("code", code);
155155+ ("client_id", client_id);
156156+ ("client_secret", client_secret);
157157+ ("redirect_uri", redirect_uri);
158158+ ("code_verifier", code_verifier);
159159+ ]
160160+ in
145161 let body = Requests.Body.form params in
146162 let resp = Requests.post requests ~body url in
147163 let status = Requests.Response.status_code resp in
···153169154170(** Verify credentials and get account info *)
155171let verify_credentials requests ~instance ~access_token =
156156- let url = Printf.sprintf "https://%s/api/v1/accounts/verify_credentials" instance in
172172+ let url =
173173+ Printf.sprintf "https://%s/api/v1/accounts/verify_credentials" instance
174174+ in
157175 let headers =
158158- Requests.Headers.empty
159159- |> Requests.Headers.bearer access_token
176176+ Requests.Headers.empty |> Requests.Headers.bearer access_token
160177 in
161178 let resp = Requests.get requests ~headers url in
162179 let status = Requests.Response.status_code resp in
···164181 Ok (Requests.Response.jsonv account_jsont resp)
165182 else
166183 let body = Requests.Response.text resp in
167167- Error (Printf.sprintf "Failed to verify credentials (HTTP %d): %s" status body)
184184+ Error
185185+ (Printf.sprintf "Failed to verify credentials (HTTP %d): %s" status body)
168186169187(** Get the ActivityPub actor URI from a Mastodon account URL *)
170188let actor_uri_of_account_url url =
+341-342
lib/client/apubt.ml
···3131 | Network_error msg -> Format.fprintf fmt "Network error: %s" msg
3232 | Invalid_actor msg -> Format.fprintf fmt "Invalid actor: %s" msg
33333434- let to_string t =
3535- Format.asprintf "%a" pp t
3434+ let to_string t = Format.asprintf "%a" pp t
3635end
37363837exception E of Error.t
···46454746 (** ActivityPub signing components: @method, @authority, @path, date, digest, content-type *)
4847 let activitypub_components =
4949- Requests.Signature.Component.[
5050- method_;
5151- authority;
5252- path;
5353- date;
5454- content_digest;
5555- content_type;
5656- ]
4848+ Requests.Signature.Component.
4949+ [ method_; authority; path; date; content_digest; content_type ]
57505851 let create ~key_id ~key () =
5959- let config = Requests.Signature.config
6060- ~key
6161- ~keyid:key_id
6262- ~components:activitypub_components
6363- ()
5252+ let config =
5353+ Requests.Signature.config ~key ~keyid:key_id
5454+ ~components:activitypub_components ()
6455 in
6556 { key_id; key; config }
6657···7061 | Ok (`RSA priv) ->
7162 let key = Requests.Signature.Key.rsa ~priv in
7263 Ok (create ~key_id ~key ())
7373- | Ok _ ->
7474- Error "Only RSA keys are supported for ActivityPub signatures"
7575- | Error (`Msg msg) ->
7676- Error ("Failed to parse PEM key: " ^ msg)
6464+ | Ok _ -> Error "Only RSA keys are supported for ActivityPub signatures"
6565+ | Error (`Msg msg) -> Error ("Failed to parse PEM key: " ^ msg)
77667867 let from_pem_exn ~key_id ~pem () =
7968 match from_pem ~key_id ~pem () with
···8473 let key t = t.key
8574end
86758787-type t = T : {
8888- requests : Requests.t;
8989- clock : _ Eio.Time.clock;
9090- signing : Signing.t option;
9191- user_agent : string;
9292-} -> t
7676+type t =
7777+ | T : {
7878+ requests : Requests.t;
7979+ clock : _ Eio.Time.clock;
8080+ signing : Signing.t option;
8181+ user_agent : string;
8282+ }
8383+ -> t
93849485let activitypub_accept =
9595- "application/activity+json, application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
8686+ "application/activity+json, application/ld+json; \
8787+ profile=\"https://www.w3.org/ns/activitystreams\""
96889789let create ~sw ?signing ?(user_agent = "Apubt/0.1") ?(timeout = 30.0) env =
9890 let timeout_config = Requests.Timeout.v ~connect:timeout ~read:timeout () in
···143135 let sign_post_request (T t) ~uri ~body ~headers =
144136 match t.signing with
145137 | None -> headers
146146- | Some signing ->
138138+ | Some signing -> (
147139 (* Add Date header using the session clock *)
148140 let now_float = Eio.Time.now t.clock in
149141 let now = Ptime.of_float_s now_float |> Option.get in
150142 let date_str = Requests.Headers.http_date_of_ptime now in
151143 let headers = Requests.Headers.set `Date date_str headers in
152144 (* Create request context for signing *)
153153- let ctx = Requests.Signature.Context.request
154154- ~method_:`POST
155155- ~uri
156156- ~headers
145145+ let ctx =
146146+ Requests.Signature.Context.request ~method_:`POST ~uri ~headers
157147 in
158148 (* Sign with digest (adds Content-Digest header and signs) *)
159159- match Requests.Signature.sign_with_digest
160160- ~clock:t.clock
161161- ~config:signing.config
162162- ~context:ctx
163163- ~headers
164164- ~body
165165- ~digest_algorithm:`Sha256
149149+ match
150150+ Requests.Signature.sign_with_digest ~clock:t.clock
151151+ ~config:signing.config ~context:ctx ~headers ~body
152152+ ~digest_algorithm:`Sha256
166153 with
167154 | Ok signed_headers -> signed_headers
168155 | Error err ->
169156 let msg = Requests.Signature.sign_error_to_string err in
170170- raise (E (Signature_error msg))
157157+ raise (E (Signature_error msg)))
171158172159 (* Helper to encode JSON to string, raising on error *)
173160 let encode_json_exn jsont value =
···183170 |> Requests.Headers.set `Content_type "application/activity+json"
184171 in
185172 let headers = sign_post_request client ~uri ~body:body_str ~headers in
186186- let resp = Requests.post t.requests ~headers ~body:(Requests.Body.of_string Requests.Mime.json body_str) url in
173173+ let resp =
174174+ Requests.post t.requests ~headers
175175+ ~body:(Requests.Body.of_string Requests.Mime.json body_str)
176176+ url
177177+ in
187178 check_response resp
188179189180 let post_typed (T t as client) jsont uri value =
···194185 |> Requests.Headers.set `Content_type "application/activity+json"
195186 in
196187 let headers = sign_post_request client ~uri ~body:body_str ~headers in
197197- let resp = Requests.post t.requests ~headers ~body:(Requests.Body.of_string Requests.Mime.json body_str) url in
188188+ let resp =
189189+ Requests.post t.requests ~headers
190190+ ~body:(Requests.Body.of_string Requests.Mime.json body_str)
191191+ url
192192+ in
198193 check_response resp
199194end
200195201196module Webfinger = struct
202197 (** Convert a webfinger library Jrd to our internal Proto.Webfinger type *)
203198 let jrd_of_webfinger (jrd : Webfinger.Jrd.t) : Proto.Webfinger.t =
204204- let links = List.map (fun (link : Webfinger.Link.t) ->
205205- Proto.Webfinger.Jrd_link.make
206206- ~rel:(Webfinger.Link.rel link)
207207- ?type_:(Webfinger.Link.type_ link)
208208- ?href:(Option.map Uri.of_string (Webfinger.Link.href link))
209209- ?template:(
210210- (* Try to get template from properties if it exists *)
211211- Webfinger.Link.property ~uri:"template" link
212212- )
213213- ()
214214- ) (Webfinger.Jrd.links jrd) in
215215- let aliases = match Webfinger.Jrd.aliases jrd with
216216- | [] -> None
217217- | a -> Some a
199199+ let links =
200200+ List.map
201201+ (fun (link : Webfinger.Link.t) ->
202202+ Proto.Webfinger.Jrd_link.make ~rel:(Webfinger.Link.rel link)
203203+ ?type_:(Webfinger.Link.type_ link)
204204+ ?href:(Option.map Uri.of_string (Webfinger.Link.href link))
205205+ ?template:
206206+ ((* Try to get template from properties if it exists *)
207207+ Webfinger.Link.property ~uri:"template" link)
208208+ ())
209209+ (Webfinger.Jrd.links jrd)
210210+ in
211211+ let aliases =
212212+ match Webfinger.Jrd.aliases jrd with [] -> None | a -> Some a
218213 in
219219- let properties = match Webfinger.Jrd.properties jrd with
214214+ let properties =
215215+ match Webfinger.Jrd.properties jrd with
220216 | [] -> None
221221- | p -> Some (List.filter_map (fun (k, v) ->
222222- match v with Some s -> Some (k, s) | None -> None
223223- ) p)
217217+ | p ->
218218+ Some
219219+ (List.filter_map
220220+ (fun (k, v) ->
221221+ match v with Some s -> Some (k, s) | None -> None)
222222+ p)
224223 in
225224 Proto.Webfinger.make
226225 ~subject:(Option.value ~default:"" (Webfinger.Jrd.subject jrd))
227227- ?aliases
228228- ?properties
229229- ~links
230230- ()
226226+ ?aliases ?properties ~links ()
231227232228 let lookup (T t) acct =
233229 (* Parse the account string into an Acct.t *)
234230 let acct_uri =
235231 (* Handle both "user@domain" and "acct:user@domain" formats *)
236232 let acct_str =
237237- if String.starts_with ~prefix:"acct:" acct then acct
238238- else "acct:" ^ acct
233233+ if String.starts_with ~prefix:"acct:" acct then acct else "acct:" ^ acct
239234 in
240235 match Webfinger.Acct.of_string acct_str with
241236 | Ok a -> a
···250245 let lookup_raw (T t) acct =
251246 let acct_uri =
252247 let acct_str =
253253- if String.starts_with ~prefix:"acct:" acct then acct
254254- else "acct:" ^ acct
248248+ if String.starts_with ~prefix:"acct:" acct then acct else "acct:" ^ acct
255249 in
256250 match Webfinger.Acct.of_string acct_str with
257251 | Ok a -> a
···265259 match Proto.Webfinger.links jrd with
266260 | None -> None
267261 | Some links ->
268268- List.find_map (fun link ->
269269- if Proto.Webfinger.Jrd_link.rel link = Webfinger.Rel.activitypub then
270270- match Proto.Webfinger.Jrd_link.type_ link with
271271- | Some t when String.equal t "application/activity+json" ->
272272- Proto.Webfinger.Jrd_link.href link
273273- | Some t when String.starts_with ~prefix:"application/ld+json" t ->
274274- Proto.Webfinger.Jrd_link.href link
275275- | _ -> None
276276- else None
277277- ) links
262262+ List.find_map
263263+ (fun link ->
264264+ if Proto.Webfinger.Jrd_link.rel link = Webfinger.Rel.activitypub
265265+ then
266266+ match Proto.Webfinger.Jrd_link.type_ link with
267267+ | Some t when String.equal t "application/activity+json" ->
268268+ Proto.Webfinger.Jrd_link.href link
269269+ | Some t when String.starts_with ~prefix:"application/ld+json" t
270270+ ->
271271+ Proto.Webfinger.Jrd_link.href link
272272+ | _ -> None
273273+ else None)
274274+ links
278275279276 (** Extract ActivityPub actor URI from a raw Webfinger.Jrd.t *)
280277 let actor_uri_raw (jrd : Webfinger.Jrd.t) : Uri.t option =
281278 (* Look for self link with ActivityPub media type *)
282279 match Webfinger.Jrd.find_link ~rel:Webfinger.Rel.activitypub jrd with
283283- | Some link ->
284284- (match Webfinger.Link.type_ link with
285285- | Some t when String.equal t "application/activity+json" ->
286286- Option.map Uri.of_string (Webfinger.Link.href link)
287287- | Some t when String.starts_with ~prefix:"application/ld+json" t ->
288288- Option.map Uri.of_string (Webfinger.Link.href link)
289289- | _ -> None)
280280+ | Some link -> (
281281+ match Webfinger.Link.type_ link with
282282+ | Some t when String.equal t "application/activity+json" ->
283283+ Option.map Uri.of_string (Webfinger.Link.href link)
284284+ | Some t when String.starts_with ~prefix:"application/ld+json" t ->
285285+ Option.map Uri.of_string (Webfinger.Link.href link)
286286+ | _ -> None)
290287 | None -> None
291288292289 let profile_page jrd =
293290 match Proto.Webfinger.links jrd with
294291 | None -> None
295292 | Some links ->
296296- List.find_map (fun link ->
297297- if Proto.Webfinger.Jrd_link.rel link = Webfinger.Rel.profile then
298298- Proto.Webfinger.Jrd_link.href link
299299- else None
300300- ) links
293293+ List.find_map
294294+ (fun link ->
295295+ if Proto.Webfinger.Jrd_link.rel link = Webfinger.Rel.profile then
296296+ Proto.Webfinger.Jrd_link.href link
297297+ else None)
298298+ links
301299302300 let subscribe_template jrd =
303301 match Proto.Webfinger.links jrd with
304302 | None -> None
305303 | Some links ->
306306- List.find_map (fun link ->
307307- if Proto.Webfinger.Jrd_link.rel link = Webfinger.Rel.subscribe then
308308- Proto.Webfinger.Jrd_link.template link
309309- else None
310310- ) links
304304+ List.find_map
305305+ (fun link ->
306306+ if Proto.Webfinger.Jrd_link.rel link = Webfinger.Rel.subscribe then
307307+ Proto.Webfinger.Jrd_link.template link
308308+ else None)
309309+ links
311310end
312311313312module Nodeinfo = struct
314313 (* Well-known nodeinfo link structure *)
315314 module Well_known_link = struct
316316- type t = {
317317- rel : string;
318318- href : string;
319319- }
315315+ type t = { rel : string; href : string }
320316321317 let jsont =
322322- Json.Codec.Object.map ~kind:"WellKnownLink"
323323- (fun rel href -> { rel; href })
318318+ Json.Codec.Object.map ~kind:"WellKnownLink" (fun rel href ->
319319+ { rel; href })
324320 |> Json.Codec.Object.member "rel" Json.Codec.string ~enc:(fun t -> t.rel)
325325- |> Json.Codec.Object.member "href" Json.Codec.string ~enc:(fun t -> t.href)
321321+ |> Json.Codec.Object.member "href" Json.Codec.string ~enc:(fun t ->
322322+ t.href)
326323 |> Json.Codec.Object.seal
327324 end
328325329326 module Well_known = struct
330330- type t = {
331331- links : Well_known_link.t list;
332332- }
327327+ type t = { links : Well_known_link.t list }
333328334329 let jsont =
335335- Json.Codec.Object.map ~kind:"WellKnownNodeinfo"
336336- (fun links -> { links })
337337- |> Json.Codec.Object.member "links" (Json.Codec.list Well_known_link.jsont)
338338- ~enc:(fun t -> t.links)
330330+ Json.Codec.Object.map ~kind:"WellKnownNodeinfo" (fun links -> { links })
331331+ |> Json.Codec.Object.member "links"
332332+ (Json.Codec.list Well_known_link.jsont) ~enc:(fun t -> t.links)
339333 |> Json.Codec.Object.seal
340334 end
341335342336 let fetch (T t) ~host =
343337 (* Step 1: Fetch the well-known nodeinfo discovery document *)
344344- let well_known_url = Printf.sprintf "https://%s/.well-known/nodeinfo" host in
338338+ let well_known_url =
339339+ Printf.sprintf "https://%s/.well-known/nodeinfo" host
340340+ in
345341 let headers =
346346- Requests.Headers.empty
347347- |> Requests.Headers.add `Accept "application/json"
342342+ Requests.Headers.empty |> Requests.Headers.add `Accept "application/json"
348343 in
349344 let resp = Requests.get t.requests ~headers well_known_url in
350345 check_response resp;
351346 let well_known = Requests.Response.jsonv Well_known.jsont resp in
352347 (* Step 2: Find a link with rel containing "nodeinfo" and schema 2.0 or 2.1 *)
353348 let nodeinfo_href =
354354- List.find_map (fun (link : Well_known_link.t) ->
355355- (* Check if rel contains nodeinfo and is schema 2.0 or 2.1 *)
356356- if String.length link.rel > 0 &&
357357- (String.ends_with ~suffix:"/schema/2.0" link.rel ||
358358- String.ends_with ~suffix:"/schema/2.1" link.rel)
359359- then Some link.href
360360- else None
361361- ) well_known.links
349349+ List.find_map
350350+ (fun (link : Well_known_link.t) ->
351351+ (* Check if rel contains nodeinfo and is schema 2.0 or 2.1 *)
352352+ if
353353+ String.length link.rel > 0
354354+ && (String.ends_with ~suffix:"/schema/2.0" link.rel
355355+ || String.ends_with ~suffix:"/schema/2.1" link.rel)
356356+ then Some link.href
357357+ else None)
358358+ well_known.links
362359 in
363360 match nodeinfo_href with
364364- | None -> raise (E (Json_error "No NodeInfo 2.0 or 2.1 link found in well-known response"))
361361+ | None ->
362362+ raise
363363+ (E
364364+ (Json_error
365365+ "No NodeInfo 2.0 or 2.1 link found in well-known response"))
365366 | Some href ->
366367 (* Step 3: Fetch the actual NodeInfo document *)
367368 let resp = Requests.get t.requests ~headers href in
···379380end
380381381382module Actor = struct
382382- let fetch t uri =
383383- Http.get_typed t Proto.Actor.jsont uri
383383+ let fetch t uri = Http.get_typed t Proto.Actor.jsont uri
384384385385 let lookup t acct =
386386 (* Use the raw webfinger lookup for efficiency - avoids converting to Proto.Webfinger *)
387387 let jrd = Webfinger.lookup_raw t acct in
388388 match Webfinger.actor_uri_raw jrd with
389389 | Some uri -> fetch t uri
390390- | None -> raise (E (Webfinger_error "No ActivityPub actor link in Webfinger response"))
390390+ | None ->
391391+ raise
392392+ (E (Webfinger_error "No ActivityPub actor link in Webfinger response"))
391393392394 let inbox _t actor = Proto.Actor.inbox actor
393395···396398 Http.get_typed t Proto.Activity_collection.jsont uri
397399398400 let outbox_page t actor ?page () =
399399- let uri = match page with
401401+ let uri =
402402+ match page with
400403 | Some p -> p
401401- | None ->
404404+ | None -> (
402405 let collection = outbox t actor in
403406 match Proto.Collection.first collection with
404407 | Some first -> first
405405- | None -> raise (E (Invalid_actor "Outbox has no first page"))
408408+ | None -> raise (E (Invalid_actor "Outbox has no first page")))
406409 in
407410 Http.get_typed t Proto.Activity_collection_page.jsont uri
408411409412 let followers t actor =
410413 match Proto.Actor.followers actor with
411411- | Some uri -> Http.get_typed t (Proto.Collection.jsont Proto.Actor.jsont) uri
414414+ | Some uri ->
415415+ Http.get_typed t (Proto.Collection.jsont Proto.Actor.jsont) uri
412416 | None -> raise (E (Invalid_actor "Actor has no followers collection"))
413417414418 let following t actor =
415419 match Proto.Actor.following actor with
416416- | Some uri -> Http.get_typed t (Proto.Collection.jsont Proto.Actor.jsont) uri
420420+ | Some uri ->
421421+ Http.get_typed t (Proto.Collection.jsont Proto.Actor.jsont) uri
417422 | None -> raise (E (Invalid_actor "Actor has no following collection"))
418423419424 (* Helper to post activity to an actor's inbox *)
···423428424429 let follow t ~actor ~target =
425430 (* Create a Follow activity: actor follows target *)
426426- let follow_activity = Proto.Activity.make
427427- ~context:Proto.Context.default
428428- ~type_:Proto.Activity_type.Follow
429429- ~actor:(Proto.Actor_ref.actor actor)
430430- ~object_:(Proto.Object_ref.uri (Proto.Actor.id target))
431431- ()
431431+ let follow_activity =
432432+ Proto.Activity.make ~context:Proto.Context.default
433433+ ~type_:Proto.Activity_type.Follow
434434+ ~actor:(Proto.Actor_ref.actor actor)
435435+ ~object_:(Proto.Object_ref.uri (Proto.Actor.id target))
436436+ ()
432437 in
433438 (* Deliver to target's inbox *)
434439 post_to_inbox t target follow_activity;
···436441437442 let unfollow t ~actor ~target =
438443 (* Create a Follow activity representing the original follow *)
439439- let follow_activity = Proto.Activity.make
440440- ~type_:Proto.Activity_type.Follow
441441- ~actor:(Proto.Actor_ref.actor actor)
442442- ~object_:(Proto.Object_ref.uri (Proto.Actor.id target))
443443- ()
444444+ let follow_activity =
445445+ Proto.Activity.make ~type_:Proto.Activity_type.Follow
446446+ ~actor:(Proto.Actor_ref.actor actor)
447447+ ~object_:(Proto.Object_ref.uri (Proto.Actor.id target))
448448+ ()
444449 in
445450 (* Wrap in an Undo activity *)
446446- let undo_activity = Proto.Activity.make
447447- ~context:Proto.Context.default
448448- ~type_:Proto.Activity_type.Undo
449449- ~actor:(Proto.Actor_ref.actor actor)
450450- ~object_:(Proto.Object_ref.uri (
451451- match Proto.Activity.id follow_activity with
452452- | Some id -> id
453453- | None -> Proto.Actor.id actor (* fallback: use actor ID as base *)
454454- ))
455455- ()
451451+ let undo_activity =
452452+ Proto.Activity.make ~context:Proto.Context.default
453453+ ~type_:Proto.Activity_type.Undo
454454+ ~actor:(Proto.Actor_ref.actor actor)
455455+ ~object_:
456456+ (Proto.Object_ref.uri
457457+ (match Proto.Activity.id follow_activity with
458458+ | Some id -> id
459459+ | None -> Proto.Actor.id actor (* fallback: use actor ID as base *)))
460460+ ()
456461 in
457462 (* Deliver to target's inbox *)
458463 post_to_inbox t target undo_activity;
···461466 let accept_follow t ~actor ~follow =
462467 (* Create an Accept activity *)
463468 (* The object is the Follow activity being accepted *)
464464- let follow_ref = match Proto.Activity.id follow with
469469+ let follow_ref =
470470+ match Proto.Activity.id follow with
465471 | Some id -> Proto.Object_ref.uri id
466472 | None ->
467473 (* If the follow has no ID, we need to reference it somehow.
468474 In practice, Follow activities should always have IDs. *)
469475 Proto.Object_ref.uri (Proto.Actor.id actor)
470476 in
471471- let accept_activity = Proto.Activity.make
472472- ~context:Proto.Context.default
473473- ~type_:Proto.Activity_type.Accept
474474- ~actor:(Proto.Actor_ref.actor actor)
475475- ~object_:follow_ref
476476- ()
477477+ let accept_activity =
478478+ Proto.Activity.make ~context:Proto.Context.default
479479+ ~type_:Proto.Activity_type.Accept
480480+ ~actor:(Proto.Actor_ref.actor actor)
481481+ ~object_:follow_ref ()
477482 in
478483 (* Get the follower's URI from the Follow activity's actor *)
479479- let follower_uri = match Proto.Activity.actor follow with
484484+ let follower_uri =
485485+ match Proto.Activity.actor follow with
480486 | Proto.Actor_ref.Uri uri -> uri
481487 | Proto.Actor_ref.Actor a -> Proto.Actor.id a
482488 in
···488494 let reject_follow t ~actor ~follow =
489495 (* Create a Reject activity *)
490496 (* The object is the Follow activity being rejected *)
491491- let follow_ref = match Proto.Activity.id follow with
497497+ let follow_ref =
498498+ match Proto.Activity.id follow with
492499 | Some id -> Proto.Object_ref.uri id
493500 | None ->
494501 (* If the follow has no ID, we need to reference it somehow.
495502 In practice, Follow activities should always have IDs. *)
496503 Proto.Object_ref.uri (Proto.Actor.id actor)
497504 in
498498- let reject_activity = Proto.Activity.make
499499- ~context:Proto.Context.default
500500- ~type_:Proto.Activity_type.Reject
501501- ~actor:(Proto.Actor_ref.actor actor)
502502- ~object_:follow_ref
503503- ()
505505+ let reject_activity =
506506+ Proto.Activity.make ~context:Proto.Context.default
507507+ ~type_:Proto.Activity_type.Reject
508508+ ~actor:(Proto.Actor_ref.actor actor)
509509+ ~object_:follow_ref ()
504510 in
505511 (* Get the follower's URI from the Follow activity's actor *)
506506- let follower_uri = match Proto.Activity.actor follow with
512512+ let follower_uri =
513513+ match Proto.Activity.actor follow with
507514 | Proto.Actor_ref.Uri uri -> uri
508515 | Proto.Actor_ref.Actor a -> Proto.Actor.id a
509516 in
···514521end
515522516523module Object = struct
517517- let fetch t uri =
518518- Http.get_typed t Proto.Object.jsont uri
524524+ let fetch t uri = Http.get_typed t Proto.Object.jsont uri
519525520526 let replies t obj =
521527 match Proto.Object.replies obj with
···536542 let instance_actor_url = Printf.sprintf "https://%s/actor" host in
537543 try
538544 let resp = Requests.get t.requests instance_actor_url in
539539- if Requests.Response.status_code resp >= 200 &&
540540- Requests.Response.status_code resp < 300 then begin
545545+ if
546546+ Requests.Response.status_code resp >= 200
547547+ && Requests.Response.status_code resp < 300
548548+ then begin
541549 let actor = Requests.Response.jsonv Proto.Actor.jsont resp in
542550 match Proto.Actor.endpoints actor with
543543- | Some endpoints ->
544544- Proto.Endpoints.shared_inbox endpoints
551551+ | Some endpoints -> Proto.Endpoints.shared_inbox endpoints
545552 | None -> None
546546- end else
547547- None
553553+ end
554554+ else None
548555 with _ ->
549556 (* If fetching instance actor fails, there's no shared inbox *)
550557 None
551558552559 let post_to_shared_inbox t ~host activity =
553560 match discover_shared_inbox t ~host with
554554- | Some shared_inbox ->
555555- post t ~inbox:shared_inbox activity
561561+ | Some shared_inbox -> post t ~inbox:shared_inbox activity
556562 | None ->
557563 (* Fallback: construct a standard shared inbox URL *)
558558- let shared_inbox = Uri.of_string (Printf.sprintf "https://%s/inbox" host) in
564564+ let shared_inbox =
565565+ Uri.of_string (Printf.sprintf "https://%s/inbox" host)
566566+ in
559567 post t ~inbox:shared_inbox activity
560568end
561569···577585578586 (* Extract inbox URIs from a list of recipients, resolving actors as needed *)
579587 let resolve_recipient_inboxes t recipients =
580580- List.filter_map (fun recipient ->
581581- let uri = Proto.Recipient.id recipient in
582582- let uri_str = Uri.to_string uri in
583583- (* Skip the public collection - it doesn't have an inbox *)
584584- if String.equal uri_str (Uri.to_string Proto.Public.id) then
585585- None
586586- else begin
587587- (* Try to fetch the actor to get their inbox *)
588588- try
589589- let actor = Actor.fetch t uri in
590590- Some (Proto.Actor.inbox actor)
591591- with E _ ->
592592- (* If we can't fetch the actor, skip this recipient *)
593593- None
594594- end
595595- ) recipients
588588+ List.filter_map
589589+ (fun recipient ->
590590+ let uri = Proto.Recipient.id recipient in
591591+ let uri_str = Uri.to_string uri in
592592+ (* Skip the public collection - it doesn't have an inbox *)
593593+ if String.equal uri_str (Uri.to_string Proto.Public.id) then None
594594+ else
595595+ (* Try to fetch the actor to get their inbox *)
596596+ begin try
597597+ let actor = Actor.fetch t uri in
598598+ Some (Proto.Actor.inbox actor)
599599+ with E _ ->
600600+ (* If we can't fetch the actor, skip this recipient *)
601601+ None
602602+ end)
603603+ recipients
596604597605 (* Deliver an activity to all recipients in to/cc *)
598606 let deliver t activity =
599599- let to_recipients = Option.value ~default:[] (Proto.Activity.to_ activity) in
607607+ let to_recipients =
608608+ Option.value ~default:[] (Proto.Activity.to_ activity)
609609+ in
600610 let cc_recipients = Option.value ~default:[] (Proto.Activity.cc activity) in
601611 let all_recipients = to_recipients @ cc_recipients in
602612 let inboxes = resolve_recipient_inboxes t all_recipients in
603613 (* Deduplicate inboxes *)
604614 let seen = Hashtbl.create 16 in
605605- let unique_inboxes = List.filter (fun inbox ->
606606- let uri_str = Uri.to_string inbox in
607607- if Hashtbl.mem seen uri_str then false
608608- else begin
609609- Hashtbl.add seen uri_str ();
610610- true
611611- end
612612- ) inboxes in
615615+ let unique_inboxes =
616616+ List.filter
617617+ (fun inbox ->
618618+ let uri_str = Uri.to_string inbox in
619619+ if Hashtbl.mem seen uri_str then false
620620+ else begin
621621+ Hashtbl.add seen uri_str ();
622622+ true
623623+ end)
624624+ inboxes
625625+ in
613626 (* Post to each inbox *)
614614- List.iter (fun inbox ->
615615- try
616616- Inbox.post t ~inbox activity
617617- with E _ ->
618618- (* Log delivery failures but don't fail the whole operation *)
619619- ()
620620- ) unique_inboxes
627627+ List.iter
628628+ (fun inbox ->
629629+ try Inbox.post t ~inbox activity
630630+ with E _ ->
631631+ (* Log delivery failures but don't fail the whole operation *)
632632+ ())
633633+ unique_inboxes
621634622622- let create_note t ~actor ?in_reply_to ?to_ ?cc ?sensitive ?summary ~content () =
635635+ let create_note t ~actor ?in_reply_to ?to_ ?cc ?sensitive ?summary ~content ()
636636+ =
623637 let note_id = generate_uri ~actor ~suffix:"notes" in
624638 let activity_id = generate_uri ~actor ~suffix:"activities" in
625639 let published = now_datetime () in
626640 (* Build the Note object *)
627627- let note = Proto.Object.make
628628- ~context:Proto.Context.default
629629- ~id:note_id
630630- ~type_:Proto.Object_type.Note
631631- ~content
632632- ~attributed_to:(Proto.Actor_ref.uri (Proto.Actor.id actor))
633633- ?in_reply_to
634634- ?to_
635635- ?cc
636636- ?sensitive
637637- ?summary
638638- ~published
639639- ()
641641+ let note =
642642+ Proto.Object.make ~context:Proto.Context.default ~id:note_id
643643+ ~type_:Proto.Object_type.Note ~content
644644+ ~attributed_to:(Proto.Actor_ref.uri (Proto.Actor.id actor))
645645+ ?in_reply_to ?to_ ?cc ?sensitive ?summary ~published ()
640646 in
641647 (* Build the Create activity *)
642642- let activity = Proto.Activity.make
643643- ~context:Proto.Context.default
644644- ~id:activity_id
645645- ~type_:Proto.Activity_type.Create
646646- ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
647647- ~object_:(Proto.Object_ref.obj note)
648648- ?to_
649649- ?cc
650650- ~published
651651- ()
648648+ let activity =
649649+ Proto.Activity.make ~context:Proto.Context.default ~id:activity_id
650650+ ~type_:Proto.Activity_type.Create
651651+ ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
652652+ ~object_:(Proto.Object_ref.obj note)
653653+ ?to_ ?cc ~published ()
652654 in
653655 (* Deliver to all recipients *)
654656 deliver t activity;
···661663 | None -> Uri.of_string ""
662664 in
663665 create_note t ~actor ?in_reply_to
664664- ~to_:[Proto.Recipient.make Proto.Public.id]
665665- ~cc:[Proto.Recipient.make followers_uri]
666666+ ~to_:[ Proto.Recipient.make Proto.Public.id ]
667667+ ~cc:[ Proto.Recipient.make followers_uri ]
666668 ~content ()
667669668670 let followers_only_note t ~actor ?in_reply_to ~content () =
669671 let followers_uri =
670672 match Proto.Actor.followers actor with
671673 | Some uri -> uri
672672- | None -> raise (E (Error.Invalid_actor "Actor has no followers collection"))
674674+ | None ->
675675+ raise (E (Error.Invalid_actor "Actor has no followers collection"))
673676 in
674677 create_note t ~actor ?in_reply_to
675675- ~to_:[Proto.Recipient.make followers_uri]
678678+ ~to_:[ Proto.Recipient.make followers_uri ]
676679 ~content ()
677680678681 let direct_note t ~actor ~to_ ?in_reply_to ~content () =
679679- let recipients = List.map (fun a -> Proto.Recipient.make (Proto.Actor.id a)) to_ in
682682+ let recipients =
683683+ List.map (fun a -> Proto.Recipient.make (Proto.Actor.id a)) to_
684684+ in
680685 create_note t ~actor ?in_reply_to ~to_:recipients ~content ()
681686682687 let like t ~actor ~object_ =
···686691 let obj = Object.fetch t object_ in
687692 let to_recipients =
688693 match Proto.Object.attributed_to obj with
689689- | Some (Proto.Actor_ref.Uri uri) -> [Proto.Recipient.make uri]
690690- | Some (Proto.Actor_ref.Actor a) -> [Proto.Recipient.make (Proto.Actor.id a)]
694694+ | Some (Proto.Actor_ref.Uri uri) -> [ Proto.Recipient.make uri ]
695695+ | Some (Proto.Actor_ref.Actor a) ->
696696+ [ Proto.Recipient.make (Proto.Actor.id a) ]
691697 | None -> []
692698 in
693699 (* Build the Like activity *)
694694- let activity = Proto.Activity.make
695695- ~context:Proto.Context.default
696696- ~id:activity_id
697697- ~type_:Proto.Activity_type.Like
698698- ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
699699- ~object_:(Proto.Object_ref.uri object_)
700700- ~to_:to_recipients
701701- ~published
702702- ()
700700+ let activity =
701701+ Proto.Activity.make ~context:Proto.Context.default ~id:activity_id
702702+ ~type_:Proto.Activity_type.Like
703703+ ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
704704+ ~object_:(Proto.Object_ref.uri object_)
705705+ ~to_:to_recipients ~published ()
703706 in
704707 (* Deliver to the object's author *)
705708 deliver t activity;
···713716 let obj = Object.fetch t object_ in
714717 let to_recipients =
715718 match Proto.Object.attributed_to obj with
716716- | Some (Proto.Actor_ref.Uri uri) -> [Proto.Recipient.make uri]
717717- | Some (Proto.Actor_ref.Actor a) -> [Proto.Recipient.make (Proto.Actor.id a)]
719719+ | Some (Proto.Actor_ref.Uri uri) -> [ Proto.Recipient.make uri ]
720720+ | Some (Proto.Actor_ref.Actor a) ->
721721+ [ Proto.Recipient.make (Proto.Actor.id a) ]
718722 | None -> []
719723 in
720724 (* Build the Undo(Like) activity - reference the Like by URI *)
721721- let activity = Proto.Activity.make
722722- ~context:Proto.Context.default
723723- ~id:activity_id
724724- ~type_:Proto.Activity_type.Undo
725725- ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
726726- ~object_:(Proto.Object_ref.uri like_id)
727727- ~to_:to_recipients
728728- ~published
729729- ()
725725+ let activity =
726726+ Proto.Activity.make ~context:Proto.Context.default ~id:activity_id
727727+ ~type_:Proto.Activity_type.Undo
728728+ ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
729729+ ~object_:(Proto.Object_ref.uri like_id)
730730+ ~to_:to_recipients ~published ()
730731 in
731732 (* Deliver to the object's author *)
732733 deliver t activity;
···737738 let published = now_datetime () in
738739 (* Get actor's followers for cc *)
739740 let followers_uri = Proto.Actor.followers actor in
740740- let cc_recipients = match followers_uri with
741741- | Some uri -> [Proto.Recipient.make uri]
741741+ let cc_recipients =
742742+ match followers_uri with
743743+ | Some uri -> [ Proto.Recipient.make uri ]
742744 | None -> []
743745 in
744746 (* Fetch the object to find its author for delivery *)
745747 let obj = Object.fetch t object_ in
746748 let author_recipients =
747749 match Proto.Object.attributed_to obj with
748748- | Some (Proto.Actor_ref.Uri uri) -> [Proto.Recipient.make uri]
749749- | Some (Proto.Actor_ref.Actor a) -> [Proto.Recipient.make (Proto.Actor.id a)]
750750+ | Some (Proto.Actor_ref.Uri uri) -> [ Proto.Recipient.make uri ]
751751+ | Some (Proto.Actor_ref.Actor a) ->
752752+ [ Proto.Recipient.make (Proto.Actor.id a) ]
750753 | None -> []
751754 in
752755 (* to: public, author; cc: followers *)
753753- let to_recipients = Proto.Recipient.make Proto.Public.id :: author_recipients in
756756+ let to_recipients =
757757+ Proto.Recipient.make Proto.Public.id :: author_recipients
758758+ in
754759 (* Build the Announce activity *)
755755- let activity = Proto.Activity.make
756756- ~context:Proto.Context.default
757757- ~id:activity_id
758758- ~type_:Proto.Activity_type.Announce
759759- ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
760760- ~object_:(Proto.Object_ref.uri object_)
761761- ~to_:to_recipients
762762- ~cc:cc_recipients
763763- ~published
764764- ()
760760+ let activity =
761761+ Proto.Activity.make ~context:Proto.Context.default ~id:activity_id
762762+ ~type_:Proto.Activity_type.Announce
763763+ ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
764764+ ~object_:(Proto.Object_ref.uri object_)
765765+ ~to_:to_recipients ~cc:cc_recipients ~published ()
765766 in
766767 (* Deliver to followers and the object's author *)
767768 deliver t activity;
···773774 let published = now_datetime () in
774775 (* Get actor's followers for cc *)
775776 let followers_uri = Proto.Actor.followers actor in
776776- let cc_recipients = match followers_uri with
777777- | Some uri -> [Proto.Recipient.make uri]
777777+ let cc_recipients =
778778+ match followers_uri with
779779+ | Some uri -> [ Proto.Recipient.make uri ]
778780 | None -> []
779781 in
780782 (* Fetch the object to find its author for delivery *)
781783 let obj = Object.fetch t object_ in
782784 let author_recipients =
783785 match Proto.Object.attributed_to obj with
784784- | Some (Proto.Actor_ref.Uri uri) -> [Proto.Recipient.make uri]
785785- | Some (Proto.Actor_ref.Actor a) -> [Proto.Recipient.make (Proto.Actor.id a)]
786786+ | Some (Proto.Actor_ref.Uri uri) -> [ Proto.Recipient.make uri ]
787787+ | Some (Proto.Actor_ref.Actor a) ->
788788+ [ Proto.Recipient.make (Proto.Actor.id a) ]
786789 | None -> []
787790 in
788788- let to_recipients = Proto.Recipient.make Proto.Public.id :: author_recipients in
791791+ let to_recipients =
792792+ Proto.Recipient.make Proto.Public.id :: author_recipients
793793+ in
789794 (* Build the Undo(Announce) activity *)
790790- let activity = Proto.Activity.make
791791- ~context:Proto.Context.default
792792- ~id:activity_id
793793- ~type_:Proto.Activity_type.Undo
794794- ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
795795- ~object_:(Proto.Object_ref.uri announce_id)
796796- ~to_:to_recipients
797797- ~cc:cc_recipients
798798- ~published
799799- ()
795795+ let activity =
796796+ Proto.Activity.make ~context:Proto.Context.default ~id:activity_id
797797+ ~type_:Proto.Activity_type.Undo
798798+ ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
799799+ ~object_:(Proto.Object_ref.uri announce_id)
800800+ ~to_:to_recipients ~cc:cc_recipients ~published ()
800801 in
801802 (* Deliver to followers and the object's author *)
802803 deliver t activity;
···810811 let to_recipients = Option.value ~default:[] (Proto.Object.to_ obj) in
811812 let cc_recipients = Option.value ~default:[] (Proto.Object.cc obj) in
812813 (* Create a Tombstone object *)
813813- let tombstone = Proto.Object.make
814814- ~id:object_
815815- ~type_:Proto.Object_type.Tombstone
816816- ~published
817817- ()
814814+ let tombstone =
815815+ Proto.Object.make ~id:object_ ~type_:Proto.Object_type.Tombstone
816816+ ~published ()
818817 in
819818 (* Build the Delete activity *)
820820- let activity = Proto.Activity.make
821821- ~context:Proto.Context.default
822822- ~id:activity_id
823823- ~type_:Proto.Activity_type.Delete
824824- ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
825825- ~object_:(Proto.Object_ref.obj tombstone)
826826- ~to_:to_recipients
827827- ~cc:cc_recipients
828828- ~published
829829- ()
819819+ let activity =
820820+ Proto.Activity.make ~context:Proto.Context.default ~id:activity_id
821821+ ~type_:Proto.Activity_type.Delete
822822+ ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
823823+ ~object_:(Proto.Object_ref.obj tombstone)
824824+ ~to_:to_recipients ~cc:cc_recipients ~published ()
830825 in
831826 (* Deliver to previous recipients *)
832827 deliver t activity;
···840835 let to_recipients = Option.value ~default:[] (Proto.Object.to_ original) in
841836 let cc_recipients = Option.value ~default:[] (Proto.Object.cc original) in
842837 (* Create the updated Note object *)
843843- let updated_note = Proto.Object.make
844844- ~context:Proto.Context.default
845845- ~id:object_
846846- ~type_:Proto.Object_type.Note
847847- ~content
848848- ~attributed_to:(Proto.Actor_ref.uri (Proto.Actor.id actor))
849849- ?in_reply_to:(Proto.Object.in_reply_to original)
850850- ~to_:to_recipients
851851- ~cc:cc_recipients
852852- ?summary:(Proto.Object.summary original)
853853- ?sensitive:(Proto.Object.sensitive original)
854854- ~updated:published
855855- ?published:(Proto.Object.published original)
856856- ()
838838+ let updated_note =
839839+ Proto.Object.make ~context:Proto.Context.default ~id:object_
840840+ ~type_:Proto.Object_type.Note ~content
841841+ ~attributed_to:(Proto.Actor_ref.uri (Proto.Actor.id actor))
842842+ ?in_reply_to:(Proto.Object.in_reply_to original)
843843+ ~to_:to_recipients ~cc:cc_recipients
844844+ ?summary:(Proto.Object.summary original)
845845+ ?sensitive:(Proto.Object.sensitive original)
846846+ ~updated:published
847847+ ?published:(Proto.Object.published original)
848848+ ()
857849 in
858850 (* Build the Update activity *)
859859- let activity = Proto.Activity.make
860860- ~context:Proto.Context.default
861861- ~id:activity_id
862862- ~type_:Proto.Activity_type.Update
863863- ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
864864- ~object_:(Proto.Object_ref.obj updated_note)
865865- ~to_:to_recipients
866866- ~cc:cc_recipients
867867- ~published
868868- ()
851851+ let activity =
852852+ Proto.Activity.make ~context:Proto.Context.default ~id:activity_id
853853+ ~type_:Proto.Activity_type.Update
854854+ ~actor:(Proto.Actor_ref.uri (Proto.Actor.id actor))
855855+ ~object_:(Proto.Object_ref.obj updated_note)
856856+ ~to_:to_recipients ~cc:cc_recipients ~published ()
869857 in
870858 (* Deliver to recipients *)
871859 deliver t activity;
···876864 let rec iter t f collection item_jsont =
877865 (* Process items in current collection if any *)
878866 (match Proto.Collection.items collection with
879879- | Some items -> List.iter f items
880880- | None -> ());
867867+ | Some items -> List.iter f items
868868+ | None -> ());
881869 (* Fetch first page if available *)
882870 match Proto.Collection.first collection with
883871 | Some first_uri ->
884884- let page = Http.get_typed t (Proto.Collection_page.jsont item_jsont) first_uri in
872872+ let page =
873873+ Http.get_typed t (Proto.Collection_page.jsont item_jsont) first_uri
874874+ in
885875 iter_page t f page item_jsont
886876 | None -> ()
887877888878 and iter_page t f page item_jsont =
889879 (* Process items in page *)
890880 (match Proto.Collection_page.items page with
891891- | Some items -> List.iter f items
892892- | None -> ());
881881+ | Some items -> List.iter f items
882882+ | None -> ());
893883 (* Fetch next page if available *)
894884 match Proto.Collection_page.next page with
895885 | Some next_uri ->
896896- let next = Http.get_typed t (Proto.Collection_page.jsont item_jsont) next_uri in
886886+ let next =
887887+ Http.get_typed t (Proto.Collection_page.jsont item_jsont) next_uri
888888+ in
897889 iter_page t f next item_jsont
898890 | None -> ()
899891900892 let rec fold t f init collection item_jsont =
901893 (* Fold over items in current collection *)
902902- let acc = match Proto.Collection.items collection with
894894+ let acc =
895895+ match Proto.Collection.items collection with
903896 | Some items -> List.fold_left f init items
904897 | None -> init
905898 in
906899 (* Fetch first page if available *)
907900 match Proto.Collection.first collection with
908901 | Some first_uri ->
909909- let page = Http.get_typed t (Proto.Collection_page.jsont item_jsont) first_uri in
902902+ let page =
903903+ Http.get_typed t (Proto.Collection_page.jsont item_jsont) first_uri
904904+ in
910905 fold_page t f acc page item_jsont
911906 | None -> acc
912907913908 and fold_page t f acc page item_jsont =
914909 (* Fold over items in page *)
915915- let acc = match Proto.Collection_page.items page with
910910+ let acc =
911911+ match Proto.Collection_page.items page with
916912 | Some items -> List.fold_left f acc items
917913 | None -> acc
918914 in
919915 (* Fetch next page if available *)
920916 match Proto.Collection_page.next page with
921917 | Some next_uri ->
922922- let next = Http.get_typed t (Proto.Collection_page.jsont item_jsont) next_uri in
918918+ let next =
919919+ Http.get_typed t (Proto.Collection_page.jsont item_jsont) next_uri
920920+ in
923921 fold_page t f acc next item_jsont
924922 | None -> acc
925923926924 let to_list t collection item_jsont =
927927- fold t (fun acc item -> item :: acc) [] collection item_jsont
928928- |> List.rev
925925+ fold t (fun acc item -> item :: acc) [] collection item_jsont |> List.rev
929926930927 let first_page t collection item_jsont =
931928 match Proto.Collection.first collection with
932929 | Some first_uri ->
933933- Some (Http.get_typed t (Proto.Collection_page.jsont item_jsont) first_uri)
930930+ Some
931931+ (Http.get_typed t (Proto.Collection_page.jsont item_jsont) first_uri)
934932 | None -> None
935933936934 let next_page t page item_jsont =
937935 match Proto.Collection_page.next page with
938936 | Some next_uri ->
939939- Some (Http.get_typed t (Proto.Collection_page.jsont item_jsont) next_uri)
937937+ Some
938938+ (Http.get_typed t (Proto.Collection_page.jsont item_jsont) next_uri)
940939 | None -> None
941940end
+81-96
lib/client/apubt.mli
···66(** ActivityPub client library for OCaml with Eio
7788 This library provides a direct-style ActivityPub client using Eio for
99- concurrent I/O. It handles actor discovery, inbox/outbox operations,
1010- HTTP signatures, and federation with other ActivityPub servers.
99+ concurrent I/O. It handles actor discovery, inbox/outbox operations, HTTP
1010+ signatures, and federation with other ActivityPub servers.
11111212 {2 Overview}
1313···2323 {2 Example}
24242525 {[
2626- open Eio.Std
2626+ open Eio.Std
27272828- let () = Eio_main.run @@ fun env ->
2929- Switch.run @@ fun sw ->
2828+ let () =
2929+ Eio_main.run @@ fun env ->
3030+ Switch.run @@ fun sw ->
3131+ (* Create an ActivityPub client *)
3232+ let client = Apubt.create ~sw env in
30333131- (* Create an ActivityPub client *)
3232- let client = Apubt.create ~sw env in
3434+ (* Discover an actor via Webfinger *)
3535+ let actor = Apubt.Actor.lookup client "user@example.com" in
3636+ Printf.printf "Found: %s\n"
3737+ (Option.value ~default:"<none>" (Proto.Actor.name actor));
33383434- (* Discover an actor via Webfinger *)
3535- let actor = Apubt.Actor.lookup client "user@example.com" in
3636- Printf.printf "Found: %s\n" (Option.value ~default:"<none>" (Proto.Actor.name actor));
3737-3838- (* Fetch their outbox *)
3939- let outbox = Apubt.Actor.outbox client actor in
4040- List.iter (fun activity ->
3939+ (* Fetch their outbox *)
4040+ let outbox = Apubt.Actor.outbox client actor in
4141+ List.iter
4242+ (fun activity ->
4143 Printf.printf "Activity: %s\n"
4242- (Proto.Activity_type.to_string (Proto.Activity.type_ activity))
4343- ) (Option.value ~default:[] (Proto.Collection.items outbox))
4444+ (Proto.Activity_type.to_string (Proto.Activity.type_ activity)))
4545+ (Option.value ~default:[] (Proto.Collection.items outbox))
4446 ]}
45474648 {2 HTTP Signatures}
···72747375(** HTTP signature configuration for authenticated requests.
74767575- Uses RFC 9421 HTTP Message Signatures via the Requests library.
7676- ActivityPub typically uses RSA-SHA256 signatures.
7777+ Uses RFC 9421 HTTP Message Signatures via the Requests library. ActivityPub
7878+ typically uses RSA-SHA256 signatures.
77797880 The following message components are signed:
7981 - [@method] - HTTP request method
···8688 type t
8789 (** Signing configuration. *)
88908989- val create :
9090- key_id:string ->
9191- key:Requests.Signature.Key.t ->
9292- unit ->
9393- t
9191+ val create : key_id:string -> key:Requests.Signature.Key.t -> unit -> t
9492 (** [create ~key_id ~key ()] creates a signing configuration.
95939694 @param key_id The key ID URI (typically actor URI + "#main-key")
9795 @param key The cryptographic key from {!Requests.Signature.Key} *)
98969999- val from_pem :
100100- key_id:string ->
101101- pem:string ->
102102- unit ->
103103- (t, string) result
9797+ val from_pem : key_id:string -> pem:string -> unit -> (t, string) result
10498 (** [from_pem ~key_id ~pem ()] creates a signing configuration from a
10599 PEM-encoded RSA private key.
106100···108102 @param pem PEM-encoded RSA private key
109103 @return [Ok t] on success, [Error msg] if PEM parsing fails *)
110104111111- val from_pem_exn :
112112- key_id:string ->
113113- pem:string ->
114114- unit ->
115115- t
116116- (** [from_pem_exn ~key_id ~pem ()] is like {!from_pem} but raises
117117- {!E} with {!Error.Signature_error} on failure. *)
105105+ val from_pem_exn : key_id:string -> pem:string -> unit -> t
106106+ (** [from_pem_exn ~key_id ~pem ()] is like {!from_pem} but raises {!E} with
107107+ {!Error.Signature_error} on failure. *)
118108119109 val key_id : t -> string
120110 (** [key_id t] returns the key ID URI. *)
···133123 ; fs : Eio.Fs.dir_ty Eio.Path.t
134124 ; .. > ->
135125 t
136136-(** [create ~sw ?signing ?user_agent ?timeout env] creates an ActivityPub client.
126126+(** [create ~sw ?signing ?user_agent ?timeout env] creates an ActivityPub
127127+ client.
137128138129 @param sw Switch for resource management
139130 @param signing HTTP signature configuration for authenticated requests
···154145 | Signature_error of string (** HTTP signature error *)
155146 | Not_found (** Resource not found (404) *)
156147 | Unauthorized (** Authentication required or failed (401/403) *)
157157- | Rate_limited of float option (** Rate limited, with optional retry-after *)
148148+ | Rate_limited of float option
149149+ (** Rate limited, with optional retry-after *)
158150 | Network_error of string (** Network/connection error *)
159151 | Invalid_actor of string (** Actor validation failed *)
160152···174166175167 This module uses the [webfinger] library for robust RFC 7033/7565 compliance
176168 with proper acct URI handling and percent-encoding. See the
177177- {{:https://swicg.github.io/activitypub-webfinger/}ActivityPub WebFinger spec}
178178- for details on how WebFinger is used with ActivityPub.
169169+ {{:https://swicg.github.io/activitypub-webfinger/}ActivityPub WebFinger
170170+ spec} for details on how WebFinger is used with ActivityPub.
179171180172 @see <https://www.rfc-editor.org/rfc/rfc7033> RFC 7033 WebFinger
181173 @see <https://www.rfc-editor.org/rfc/rfc7565> RFC 7565 acct URI *)
···183175 val lookup : t -> string -> Proto.Webfinger.t
184176 (** [lookup client acct] performs a Webfinger lookup for the given account.
185177186186- The [acct] can be in the form "user@domain" or "acct:user@domain".
187187- Uses the [webfinger] library for proper RFC 7565 acct URI handling.
178178+ The [acct] can be in the form "user@domain" or "acct:user@domain". Uses
179179+ the [webfinger] library for proper RFC 7565 acct URI handling.
188180189181 @raise E on lookup failure *)
190182···192184 (** [lookup_raw client acct] performs a Webfinger lookup returning the raw
193185 [Webfinger.Jrd.t] from the webfinger library.
194186195195- This is more efficient when you only need to extract specific fields
196196- and don't need the full {!Proto.Webfinger.t} type.
187187+ This is more efficient when you only need to extract specific fields and
188188+ don't need the full {!Proto.Webfinger.t} type.
197189198190 @raise E on lookup failure *)
199191200192 val actor_uri : Proto.Webfinger.t -> Uri.t option
201201- (** [actor_uri jrd] extracts the ActivityPub actor URI from a Webfinger response.
193193+ (** [actor_uri jrd] extracts the ActivityPub actor URI from a Webfinger
194194+ response.
202195203196 Looks for a link with [rel="self"] and [type="application/activity+json"]
204197 or [type="application/ld+json; profile=..."].
···212205 More efficient variant that works directly with {!Webfinger.Jrd.t}. *)
213206214207 val profile_page : Proto.Webfinger.t -> Uri.t option
215215- (** [profile_page jrd] extracts the HTML profile page URI from a Webfinger response.
208208+ (** [profile_page jrd] extracts the HTML profile page URI from a Webfinger
209209+ response.
216210217211 Looks for [rel="http://webfinger.net/rel/profile-page"]. *)
218212219213 val subscribe_template : Proto.Webfinger.t -> string option
220214 (** [subscribe_template jrd] extracts the subscribe/follow template URI.
221215222222- Looks for [rel="http://ostatus.org/schema/1.0/subscribe"].
223223- This is used for remote follow buttons. The template contains [{uri}]
224224- which should be replaced with the actor to follow. *)
216216+ Looks for [rel="http://ostatus.org/schema/1.0/subscribe"]. This is used
217217+ for remote follow buttons. The template contains [{uri}] which should be
218218+ replaced with the actor to follow. *)
225219end
226220227221(** {1 NodeInfo Discovery} *)
···238232 @raise E on fetch failure *)
239233240234 val software_name : Proto.Nodeinfo.t -> string
241241- (** [software_name info] returns the server software name (e.g., "mastodon", "pleroma"). *)
235235+ (** [software_name info] returns the server software name (e.g., "mastodon",
236236+ "pleroma"). *)
242237243238 val software_version : Proto.Nodeinfo.t -> string
244239 (** [software_version info] returns the server software version. *)
245240246241 val supports_activitypub : Proto.Nodeinfo.t -> bool
247247- (** [supports_activitypub info] returns [true] if the server supports ActivityPub. *)
242242+ (** [supports_activitypub info] returns [true] if the server supports
243243+ ActivityPub. *)
248244end
249245250246(** {1 Actor Operations} *)
···300296301297 (** {2 Follow/Unfollow} *)
302298303303- val follow : t -> actor:Proto.Actor.t -> target:Proto.Actor.t -> Proto.Activity.t
299299+ val follow :
300300+ t -> actor:Proto.Actor.t -> target:Proto.Actor.t -> Proto.Activity.t
304301 (** [follow client ~actor ~target] creates and sends a Follow activity.
305302306303 The [actor] is the local actor performing the follow (requires signing).
···308305309306 @raise E on send failure *)
310307311311- val unfollow : t -> actor:Proto.Actor.t -> target:Proto.Actor.t -> Proto.Activity.t
312312- (** [unfollow client ~actor ~target] creates and sends an Undo(Follow) activity.
308308+ val unfollow :
309309+ t -> actor:Proto.Actor.t -> target:Proto.Actor.t -> Proto.Activity.t
310310+ (** [unfollow client ~actor ~target] creates and sends an Undo(Follow)
311311+ activity.
313312314313 @raise E on send failure *)
315314316315 val accept_follow :
317317- t ->
318318- actor:Proto.Actor.t ->
319319- follow:Proto.Activity.t ->
320320- Proto.Activity.t
316316+ t -> actor:Proto.Actor.t -> follow:Proto.Activity.t -> Proto.Activity.t
321317 (** [accept_follow client ~actor ~follow] accepts an incoming Follow request.
322318323319 @raise E on send failure *)
324320325321 val reject_follow :
326326- t ->
327327- actor:Proto.Actor.t ->
328328- follow:Proto.Activity.t ->
329329- Proto.Activity.t
322322+ t -> actor:Proto.Actor.t -> follow:Proto.Activity.t -> Proto.Activity.t
330323 (** [reject_follow client ~actor ~follow] rejects an incoming Follow request.
331324332325 @raise E on send failure *)
···359352 @raise E on delivery failure *)
360353361354 val post_to_actor : t -> Proto.Actor.t -> Proto.Activity.t -> unit
362362- (** [post_to_actor client actor activity] delivers an activity to an actor's inbox.
355355+ (** [post_to_actor client actor activity] delivers an activity to an actor's
356356+ inbox.
363357364358 Equivalent to [post client ~inbox:(Actor.inbox client actor) activity].
365359366360 @raise E on delivery failure *)
367361368368- val post_to_shared_inbox :
369369- t ->
370370- host:string ->
371371- Proto.Activity.t ->
372372- unit
373373- (** [post_to_shared_inbox client ~host activity] delivers to a server's shared inbox.
362362+ val post_to_shared_inbox : t -> host:string -> Proto.Activity.t -> unit
363363+ (** [post_to_shared_inbox client ~host activity] delivers to a server's shared
364364+ inbox.
374365375375- Uses the shared inbox from the server's NodeInfo if available,
376376- otherwise falls back to individual inboxes.
366366+ Uses the shared inbox from the server's NodeInfo if available, otherwise
367367+ falls back to individual inboxes.
377368378369 @raise E on delivery failure *)
379370end
···395386 content:string ->
396387 unit ->
397388 Proto.Activity.t
398398- (** [create_note client ~actor ?in_reply_to ?to_ ?cc ?sensitive ?summary ~content ()]
399399- creates and sends a Create(Note) activity.
389389+ (** [create_note client ~actor ?in_reply_to ?to_ ?cc ?sensitive ?summary
390390+ ~content ()] creates and sends a Create(Note) activity.
400391401392 @param actor The local actor creating the note
402393 @param in_reply_to URI of note being replied to
···414405 content:string ->
415406 unit ->
416407 Proto.Activity.t
417417- (** [public_note client ~actor ?in_reply_to ~content ()] creates a public note.
408408+ (** [public_note client ~actor ?in_reply_to ~content ()] creates a public
409409+ note.
418410419419- Shorthand for {!create_note} with [to_] set to the public collection
420420- and [cc] set to the actor's followers.
411411+ Shorthand for {!create_note} with [to_] set to the public collection and
412412+ [cc] set to the actor's followers.
421413422414 @raise E on send failure *)
423415···428420 content:string ->
429421 unit ->
430422 Proto.Activity.t
431431- (** [followers_only_note client ~actor ?in_reply_to ~content ()] creates
432432- a followers-only note.
423423+ (** [followers_only_note client ~actor ?in_reply_to ~content ()] creates a
424424+ followers-only note.
433425434426 @raise E on send failure *)
435427···441433 content:string ->
442434 unit ->
443435 Proto.Activity.t
444444- (** [direct_note client ~actor ~to_ ?in_reply_to ~content ()] creates
445445- a direct message to specific recipients.
436436+ (** [direct_note client ~actor ~to_ ?in_reply_to ~content ()] creates a direct
437437+ message to specific recipients.
446438447439 @raise E on send failure *)
448440···495487496488(** Utilities for iterating over paginated collections. *)
497489module Collection : sig
498498- val iter :
499499- t ->
500500- ('a -> unit) ->
501501- 'a Proto.Collection.t ->
502502- 'a Json.codec ->
503503- unit
504504- (** [iter client f collection item_jsont] iterates over all items in a collection,
505505- automatically fetching subsequent pages.
490490+ val iter : t -> ('a -> unit) -> 'a Proto.Collection.t -> 'a Json.codec -> unit
491491+ (** [iter client f collection item_jsont] iterates over all items in a
492492+ collection, automatically fetching subsequent pages.
506493507494 @raise E on fetch failure *)
508495···513500 'a Proto.Collection.t ->
514501 'a Json.codec ->
515502 'acc
516516- (** [fold client f init collection item_jsont] folds over all items in a collection,
517517- automatically fetching subsequent pages.
503503+ (** [fold client f init collection item_jsont] folds over all items in a
504504+ collection, automatically fetching subsequent pages.
518505519506 @raise E on fetch failure *)
520507521521- val to_list :
522522- t ->
523523- 'a Proto.Collection.t ->
524524- 'a Json.codec ->
525525- 'a list
526526- (** [to_list client collection item_jsont] returns all items in a collection as a list.
508508+ val to_list : t -> 'a Proto.Collection.t -> 'a Json.codec -> 'a list
509509+ (** [to_list client collection item_jsont] returns all items in a collection
510510+ as a list.
527511528512 Warning: This may perform many HTTP requests for large collections.
529513···534518 'a Proto.Collection.t ->
535519 'a Json.codec ->
536520 'a Proto.Collection_page.t option
537537- (** [first_page client collection item_jsont] fetches the first page of a collection.
521521+ (** [first_page client collection item_jsont] fetches the first page of a
522522+ collection.
538523539524 @raise E on fetch failure *)
540525
···5566 @see <https://www.w3.org/TR/activitypub/> ActivityPub specification
77 @see <https://www.w3.org/TR/activitystreams-core/> ActivityStreams Core
88- @see <https://www.w3.org/TR/activitystreams-vocabulary/> ActivityStreams Vocabulary *)
88+ @see <https://www.w3.org/TR/activitystreams-vocabulary/>
99+ ActivityStreams Vocabulary *)
9101011(** {1 Common Types} *)
11121213(** Timestamps in ISO 8601 format. *)
1314module Datetime : sig
1415 type t
1616+1517 val v : string -> t
1618 val to_string : t -> string
1719 val jsont : t Json.codec
1820end = struct
1921 type t = string
2222+2023 let v s = s
2124 let to_string t = t
2225 let jsont = Json.Codec.string |> Json.Codec.with_doc ~kind:"datetime"
···2932(** JSON-LD context. *)
3033module Context : sig
3134 type t
3535+3236 val default : t
3337 val jsont : t Json.codec
3438end = struct
3539 type t = Json.t
3636- let default =
3737- Json.Value.string "https://www.w3.org/ns/activitystreams"
4040+4141+ let default = Json.Value.string "https://www.w3.org/ns/activitystreams"
3842 let jsont = Json.Codec.Value.t |> Json.Codec.with_doc ~kind:"@context"
3943end
40444141-(** Helper: JSON type that accepts either a single item or an array, normalizing to a list.
4242- On encoding, always outputs an array for consistency. *)
4545+(** Helper: JSON type that accepts either a single item or an array, normalizing
4646+ to a list. On encoding, always outputs an array for consistency. *)
4347let one_or_many (item_jsont : 'a Json.codec) : 'a list Json.codec =
4448 let dec_array = Json.Codec.list item_jsont in
4545- let dec_single = Json.Codec.map item_jsont
4646- ~dec:(fun x -> [x])
4747- ~enc:(fun _ -> assert false) (* never used for encoding *)
4949+ let dec_single =
5050+ Json.Codec.map item_jsont ~dec:(fun x -> [ x ]) ~enc:(fun _ -> assert false)
5151+ (* never used for encoding *)
4852 in
4949- Json.Codec.any ~kind:"one or many"
5050- ~dec_array
5151- ~dec_string:dec_single
5353+ Json.Codec.any ~kind:"one or many" ~dec_array ~dec_string:dec_single
5254 ~dec_object:dec_single
5355 ~enc:(fun _ -> dec_array) (* always encode as array *)
5456 ()
···5658(** Helper: Nullable value - accepts null as None, value as Some value *)
5759let nullable (jsont : 'a Json.codec) : 'a option Json.codec =
5860 let dec_null = Json.Codec.null None in
5959- let dec_value = Json.Codec.map jsont
6161+ let dec_value =
6262+ Json.Codec.map jsont
6063 ~dec:(fun v -> Some v)
6164 ~enc:(function Some v -> v | None -> assert false)
6265 in
6363- Json.Codec.any ~kind:"nullable"
6464- ~dec_null
6565- ~dec_string:dec_value
6666- ~dec_number:dec_value
6767- ~dec_bool:dec_value
6868- ~dec_array:dec_value
6666+ Json.Codec.any ~kind:"nullable" ~dec_null ~dec_string:dec_value
6767+ ~dec_number:dec_value ~dec_bool:dec_value ~dec_array:dec_value
6968 ~dec_object:dec_value
7070- ~enc:(function
7171- | None -> dec_null
7272- | Some _ -> dec_value)
6969+ ~enc:(function None -> dec_null | Some _ -> dec_value)
7370 ()
74717575-(** Helper: URI that can also be an object with an id field.
7676- This handles ActivityPub fields like 'replies' that can be either
7777- a URI string or an inline Collection object. *)
7272+(** Helper: URI that can also be an object with an id field. This handles
7373+ ActivityPub fields like 'replies' that can be either a URI string or an
7474+ inline Collection object. *)
7875let uri_or_object_with_id : Uri.t Json.codec =
7976 let id_jsont =
8077 Json.Codec.Object.map ~kind:"Object with id" (fun id -> id)
8178 |> Json.Codec.Object.member "id" uri_jsont ~enc:Fun.id
8282- |> Json.Codec.Object.skip_unknown
8383- |> Json.Codec.Object.seal
7979+ |> Json.Codec.Object.skip_unknown |> Json.Codec.Object.seal
8480 in
8585- Json.Codec.any ~kind:"URI or object"
8686- ~dec_string:uri_jsont
8181+ Json.Codec.any ~kind:"URI or object" ~dec_string:uri_jsont
8782 ~dec_object:id_jsont
8883 ~enc:(fun _ -> uri_jsont)
8984 ()
90859191-9286(** {1 Link} *)
93879488(** Link objects represent references to other resources.
···10498 ?width:int ->
10599 ?preview:Uri.t ->
106100 href:Uri.t ->
107107- unit -> t
101101+ unit ->
102102+ t
108103109104 val href : t -> Uri.t
110105 val media_type : t -> string option
···113108 val height : t -> int option
114109 val width : t -> int option
115110 val preview : t -> Uri.t option
116116-117111 val jsont : t Json.codec
118112end = struct
119113 type t = {
···140134 let jsont =
141135 Json.Codec.Object.map ~kind:"Link"
142136 (fun href media_type name hreflang height width preview ->
143143- { href; media_type; name; hreflang; height; width; preview })
137137+ { href; media_type; name; hreflang; height; width; preview })
144138 |> Json.Codec.Object.member "href" uri_jsont ~enc:href
145145- |> Json.Codec.Object.opt_member "mediaType" Json.Codec.string ~enc:media_type
139139+ |> Json.Codec.Object.opt_member "mediaType" Json.Codec.string
140140+ ~enc:media_type
146141 |> Json.Codec.Object.opt_member "name" Json.Codec.string ~enc:name
147142 |> Json.Codec.Object.opt_member "hreflang" Json.Codec.string ~enc:hreflang
148143 |> Json.Codec.Object.opt_member "height" Json.Codec.int ~enc:height
···153148154149(** Reference that can be either a URI string or a Link object. *)
155150module Link_or_uri : sig
156156- type t =
157157- | Uri of Uri.t
158158- | Link of Link.t
151151+ type t = Uri of Uri.t | Link of Link.t
159152160153 val uri : Uri.t -> t
161154 val link : Link.t -> t
162155 val jsont : t Json.codec
163156end = struct
164164- type t =
165165- | Uri of Uri.t
166166- | Link of Link.t
157157+ type t = Uri of Uri.t | Link of Link.t
167158168159 let uri u = Uri u
169160 let link l = Link l
170161171162 let jsont =
172172- let dec_string = Json.Codec.map uri_jsont ~dec:(fun u -> Uri u)
173173- ~enc:(function Uri u -> u | Link _ -> assert false) in
174174- let dec_object = Json.Codec.map Link.jsont ~dec:(fun l -> Link l)
175175- ~enc:(function Link l -> l | Uri _ -> assert false) in
176176- Json.Codec.any ~kind:"Link or URI"
177177- ~dec_string ~dec_object
178178- ~enc:(function
179179- | Uri _ -> dec_string
180180- | Link _ -> dec_object)
163163+ let dec_string =
164164+ Json.Codec.map uri_jsont
165165+ ~dec:(fun u -> Uri u)
166166+ ~enc:(function Uri u -> u | Link _ -> assert false)
167167+ in
168168+ let dec_object =
169169+ Json.Codec.map Link.jsont
170170+ ~dec:(fun l -> Link l)
171171+ ~enc:(function Link l -> l | Uri _ -> assert false)
172172+ in
173173+ Json.Codec.any ~kind:"Link or URI" ~dec_string ~dec_object
174174+ ~enc:(function Uri _ -> dec_string | Link _ -> dec_object)
181175 ()
182176end
183177···195189 ?width:int ->
196190 ?height:int ->
197191 url:Link_or_uri.t ->
198198- unit -> t
192192+ unit ->
193193+ t
199194200195 val id : t -> Uri.t option
201196 val url : t -> Link_or_uri.t
···203198 val media_type : t -> string option
204199 val width : t -> int option
205200 val height : t -> int option
206206-207201 val jsont : t Json.codec
208202end = struct
209203 type t = {
···228222 let jsont =
229223 Json.Codec.Object.map ~kind:"Image"
230224 (fun id url name media_type width height ->
231231- { id; url; name; media_type; width; height })
225225+ { id; url; name; media_type; width; height })
232226 |> Json.Codec.Object.opt_member "id" uri_jsont ~enc:id
233227 |> Json.Codec.Object.member "url" Link_or_uri.jsont ~enc:url
234228 |> Json.Codec.Object.opt_member "name" Json.Codec.string ~enc:name
235235- |> Json.Codec.Object.opt_member "mediaType" Json.Codec.string ~enc:media_type
229229+ |> Json.Codec.Object.opt_member "mediaType" Json.Codec.string
230230+ ~enc:media_type
236231 |> Json.Codec.Object.opt_member "width" Json.Codec.int ~enc:width
237232 |> Json.Codec.Object.opt_member "height" Json.Codec.int ~enc:height
238233 |> Json.Codec.Object.seal
···240235241236(** Image reference - can be URI, Link, or full Image object. *)
242237module Image_ref : sig
243243- type t =
244244- | Uri of Uri.t
245245- | Link of Link.t
246246- | Image of Image.t
238238+ type t = Uri of Uri.t | Link of Link.t | Image of Image.t
247239248240 val uri : Uri.t -> t
249241 val link : Link.t -> t
250242 val image : Image.t -> t
251243 val jsont : t Json.codec
252244end = struct
253253- type t =
254254- | Uri of Uri.t
255255- | Link of Link.t
256256- | Image of Image.t
245245+ type t = Uri of Uri.t | Link of Link.t | Image of Image.t
257246258247 let uri u = Uri u
259248 let link l = Link l
···261250262251 let jsont =
263252 (* For string case: URI *)
264264- let dec_string = Json.Codec.map uri_jsont ~dec:(fun u -> Uri u)
265265- ~enc:(function Uri u -> u | _ -> assert false) in
253253+ let dec_string =
254254+ Json.Codec.map uri_jsont
255255+ ~dec:(fun u -> Uri u)
256256+ ~enc:(function Uri u -> u | _ -> assert false)
257257+ in
266258 (* For object case: either Link or Image *)
267259 let dec_object =
268260 (* Default: decode as Image if we can't determine type *)
···270262 ~dec:(fun i -> Image i)
271263 ~enc:(function Image i -> i | _ -> assert false)
272264 in
273273- Json.Codec.any ~kind:"Image reference"
274274- ~dec_string ~dec_object
275275- ~enc:(function
276276- | Uri _ -> dec_string
277277- | Link _ | Image _ -> dec_object)
265265+ Json.Codec.any ~kind:"Image reference" ~dec_string ~dec_object
266266+ ~enc:(function Uri _ -> dec_string | Link _ | Image _ -> dec_object)
278267 ()
279268end
280269···291280292281(** Recipient reference - can be URI or inline object with id and type. *)
293282module Recipient : sig
294294- type t = {
295295- id : Uri.t;
296296- type_ : string option;
297297- }
283283+ type t = { id : Uri.t; type_ : string option }
298284299285 val make : ?type_:string -> Uri.t -> t
300286 val id : t -> Uri.t
301287 val type_ : t -> string option
302288 val jsont : t Json.codec
303289end = struct
304304- type t = {
305305- id : Uri.t;
306306- type_ : string option;
307307- }
290290+ type t = { id : Uri.t; type_ : string option }
308291309292 let make ?type_ id = { id; type_ }
310293 let id t = t.id
311294 let type_ t = t.type_
312295313296 let jsont =
314314- let dec_string = Json.Codec.map uri_jsont
297297+ let dec_string =
298298+ Json.Codec.map uri_jsont
315299 ~dec:(fun u -> { id = u; type_ = None })
316316- ~enc:(fun t -> t.id) in
300300+ ~enc:(fun t -> t.id)
301301+ in
317302 let dec_object =
318318- Json.Codec.Object.map ~kind:"Recipient"
319319- (fun id type_ -> { id; type_ })
303303+ Json.Codec.Object.map ~kind:"Recipient" (fun id type_ -> { id; type_ })
320304 |> Json.Codec.Object.member "id" uri_jsont ~enc:id
321305 |> Json.Codec.Object.opt_member "type" Json.Codec.string ~enc:type_
322306 |> Json.Codec.Object.seal
323307 in
324324- Json.Codec.any ~kind:"Recipient"
325325- ~dec_string ~dec_object
308308+ Json.Codec.any ~kind:"Recipient" ~dec_string ~dec_object
326309 ~enc:(fun t ->
327327- match t.type_ with
328328- | None -> dec_string
329329- | Some _ -> dec_object)
310310+ match t.type_ with None -> dec_string | Some _ -> dec_object)
330311 ()
331312end
332313···343324 ?provide_client_key:Uri.t ->
344325 ?sign_client_key:Uri.t ->
345326 ?shared_inbox:Uri.t ->
346346- unit -> t
327327+ unit ->
328328+ t
347329348330 val proxy_url : t -> Uri.t option
349331 val oauth_authorization_endpoint : t -> Uri.t option
···351333 val provide_client_key : t -> Uri.t option
352334 val sign_client_key : t -> Uri.t option
353335 val shared_inbox : t -> Uri.t option
354354-355336 val jsont : t Json.codec
356337end = struct
357338 type t = {
···365346366347 let make ?proxy_url ?oauth_authorization_endpoint ?oauth_token_endpoint
367348 ?provide_client_key ?sign_client_key ?shared_inbox () =
368368- { proxy_url; oauth_authorization_endpoint; oauth_token_endpoint;
369369- provide_client_key; sign_client_key; shared_inbox }
349349+ {
350350+ proxy_url;
351351+ oauth_authorization_endpoint;
352352+ oauth_token_endpoint;
353353+ provide_client_key;
354354+ sign_client_key;
355355+ shared_inbox;
356356+ }
370357371358 let proxy_url t = t.proxy_url
372359 let oauth_authorization_endpoint t = t.oauth_authorization_endpoint
···377364378365 let jsont =
379366 Json.Codec.Object.map ~kind:"Endpoints"
380380- (fun proxy_url oauth_authorization_endpoint oauth_token_endpoint
381381- provide_client_key sign_client_key shared_inbox ->
382382- { proxy_url; oauth_authorization_endpoint; oauth_token_endpoint;
383383- provide_client_key; sign_client_key; shared_inbox })
367367+ (fun
368368+ proxy_url
369369+ oauth_authorization_endpoint
370370+ oauth_token_endpoint
371371+ provide_client_key
372372+ sign_client_key
373373+ shared_inbox
374374+ ->
375375+ {
376376+ proxy_url;
377377+ oauth_authorization_endpoint;
378378+ oauth_token_endpoint;
379379+ provide_client_key;
380380+ sign_client_key;
381381+ shared_inbox;
382382+ })
384383 |> Json.Codec.Object.opt_member "proxyUrl" uri_jsont ~enc:proxy_url
385384 |> Json.Codec.Object.opt_member "oauthAuthorizationEndpoint" uri_jsont
386386- ~enc:oauth_authorization_endpoint
385385+ ~enc:oauth_authorization_endpoint
387386 |> Json.Codec.Object.opt_member "oauthTokenEndpoint" uri_jsont
388388- ~enc:oauth_token_endpoint
389389- |> Json.Codec.Object.opt_member "provideClientKey" uri_jsont ~enc:provide_client_key
390390- |> Json.Codec.Object.opt_member "signClientKey" uri_jsont ~enc:sign_client_key
387387+ ~enc:oauth_token_endpoint
388388+ |> Json.Codec.Object.opt_member "provideClientKey" uri_jsont
389389+ ~enc:provide_client_key
390390+ |> Json.Codec.Object.opt_member "signClientKey" uri_jsont
391391+ ~enc:sign_client_key
391392 |> Json.Codec.Object.opt_member "sharedInbox" uri_jsont ~enc:shared_inbox
392393 |> Json.Codec.Object.seal
393394end
···398399module Public_key : sig
399400 type t
400401401401- val make :
402402- id:Uri.t ->
403403- owner:Uri.t ->
404404- public_key_pem:string ->
405405- unit -> t
406406-402402+ val make : id:Uri.t -> owner:Uri.t -> public_key_pem:string -> unit -> t
407403 val id : t -> Uri.t
408404 val owner : t -> Uri.t
409405 val public_key_pem : t -> string
410410-411406 val jsont : t Json.codec
412407end = struct
413413- type t = {
414414- id : Uri.t;
415415- owner : Uri.t;
416416- public_key_pem : string;
417417- }
408408+ type t = { id : Uri.t; owner : Uri.t; public_key_pem : string }
418409419419- let make ~id ~owner ~public_key_pem () =
420420- { id; owner; public_key_pem }
421421-410410+ let make ~id ~owner ~public_key_pem () = { id; owner; public_key_pem }
422411 let id t = t.id
423412 let owner t = t.owner
424413 let public_key_pem t = t.public_key_pem
425414426415 let jsont =
427427- Json.Codec.Object.map ~kind:"PublicKey"
428428- (fun id owner public_key_pem -> { id; owner; public_key_pem })
416416+ Json.Codec.Object.map ~kind:"PublicKey" (fun id owner public_key_pem ->
417417+ { id; owner; public_key_pem })
429418 |> Json.Codec.Object.member "id" uri_jsont ~enc:id
430419 |> Json.Codec.Object.member "owner" uri_jsont ~enc:owner
431431- |> Json.Codec.Object.member "publicKeyPem" Json.Codec.string ~enc:public_key_pem
420420+ |> Json.Codec.Object.member "publicKeyPem" Json.Codec.string
421421+ ~enc:public_key_pem
432422 |> Json.Codec.Object.seal
433423end
434424···436426437427(** Actor types enumeration. *)
438428module Actor_type : sig
439439- type t =
440440- | Person
441441- | Service
442442- | Organization
443443- | Group
444444- | Application
429429+ type t = Person | Service | Organization | Group | Application
445430446431 val to_string : t -> string
447432 val of_string : string -> t option
448433 val jsont : t Json.codec
449434end = struct
450450- type t =
451451- | Person
452452- | Service
453453- | Organization
454454- | Group
455455- | Application
435435+ type t = Person | Service | Organization | Group | Application
456436457437 let to_string = function
458438 | Person -> "Person"
···470450 | _ -> None
471451472452 let jsont =
473473- Json.Codec.enum ~kind:"ActorType" [
474474- "Person", Person;
475475- "Service", Service;
476476- "Organization", Organization;
477477- "Group", Group;
478478- "Application", Application;
479479- ]
453453+ Json.Codec.enum ~kind:"ActorType"
454454+ [
455455+ ("Person", Person);
456456+ ("Service", Service);
457457+ ("Organization", Organization);
458458+ ("Group", Group);
459459+ ("Application", Application);
460460+ ]
480461end
481462482463(** {1 Actor} *)
···511492 ?moved_to:Uri.t ->
512493 ?featured:Uri.t ->
513494 ?featured_tags:Uri.t ->
514514- unit -> t
495495+ unit ->
496496+ t
515497516498 val context : t -> Context.t option
517499 val id : t -> Uri.t
···537519 val moved_to : t -> Uri.t option
538520 val featured : t -> Uri.t option
539521 val featured_tags : t -> Uri.t option
540540-541522 val jsont : t Json.codec
542523end = struct
543524 type t = {
···567548 featured_tags : Uri.t option;
568549 }
569550570570- let make ?context ~id ~type_ ?name ?preferred_username ?summary ?url
571571- ~inbox ~outbox ?followers ?following ?liked ?streams ?endpoints
572572- ?public_key ?icon ?image ?manually_approves_followers
573573- ?also_known_as ?discoverable ?suspended ?moved_to ?featured
574574- ?featured_tags () =
575575- { context; id; type_; name; preferred_username; summary; url;
576576- inbox; outbox; followers; following; liked; streams; endpoints;
577577- public_key; icon; image; manually_approves_followers;
578578- also_known_as; discoverable; suspended; moved_to; featured;
579579- featured_tags }
551551+ let make ?context ~id ~type_ ?name ?preferred_username ?summary ?url ~inbox
552552+ ~outbox ?followers ?following ?liked ?streams ?endpoints ?public_key ?icon
553553+ ?image ?manually_approves_followers ?also_known_as ?discoverable
554554+ ?suspended ?moved_to ?featured ?featured_tags () =
555555+ {
556556+ context;
557557+ id;
558558+ type_;
559559+ name;
560560+ preferred_username;
561561+ summary;
562562+ url;
563563+ inbox;
564564+ outbox;
565565+ followers;
566566+ following;
567567+ liked;
568568+ streams;
569569+ endpoints;
570570+ public_key;
571571+ icon;
572572+ image;
573573+ manually_approves_followers;
574574+ also_known_as;
575575+ discoverable;
576576+ suspended;
577577+ moved_to;
578578+ featured;
579579+ featured_tags;
580580+ }
580581581582 let context t = t.context
582583 let id t = t.id
···605606606607 let jsont =
607608 Json.Codec.Object.map ~kind:"Actor"
608608- (fun context id type_ name preferred_username summary url inbox outbox
609609- followers following liked streams endpoints public_key icon image
610610- manually_approves_followers also_known_as discoverable suspended
611611- moved_to featured featured_tags ->
612612- { context; id; type_; name; preferred_username; summary; url;
613613- inbox; outbox; followers; following; liked; streams; endpoints;
614614- public_key; icon; image; manually_approves_followers;
615615- also_known_as; discoverable; suspended; moved_to; featured;
616616- featured_tags })
609609+ (fun
610610+ context
611611+ id
612612+ type_
613613+ name
614614+ preferred_username
615615+ summary
616616+ url
617617+ inbox
618618+ outbox
619619+ followers
620620+ following
621621+ liked
622622+ streams
623623+ endpoints
624624+ public_key
625625+ icon
626626+ image
627627+ manually_approves_followers
628628+ also_known_as
629629+ discoverable
630630+ suspended
631631+ moved_to
632632+ featured
633633+ featured_tags
634634+ ->
635635+ {
636636+ context;
637637+ id;
638638+ type_;
639639+ name;
640640+ preferred_username;
641641+ summary;
642642+ url;
643643+ inbox;
644644+ outbox;
645645+ followers;
646646+ following;
647647+ liked;
648648+ streams;
649649+ endpoints;
650650+ public_key;
651651+ icon;
652652+ image;
653653+ manually_approves_followers;
654654+ also_known_as;
655655+ discoverable;
656656+ suspended;
657657+ moved_to;
658658+ featured;
659659+ featured_tags;
660660+ })
617661 |> Json.Codec.Object.opt_member "@context" Context.jsont ~enc:context
618662 |> Json.Codec.Object.member "id" uri_jsont ~enc:id
619663 |> Json.Codec.Object.member "type" Actor_type.jsont ~enc:type_
620664 |> Json.Codec.Object.opt_member "name" Json.Codec.string ~enc:name
621665 |> Json.Codec.Object.opt_member "preferredUsername" Json.Codec.string
622622- ~enc:preferred_username
666666+ ~enc:preferred_username
623667 |> Json.Codec.Object.opt_member "summary" Json.Codec.string ~enc:summary
624668 |> Json.Codec.Object.opt_member "url" uri_jsont ~enc:url
625669 |> Json.Codec.Object.member "inbox" uri_jsont ~enc:inbox
···627671 |> Json.Codec.Object.opt_member "followers" uri_jsont ~enc:followers
628672 |> Json.Codec.Object.opt_member "following" uri_jsont ~enc:following
629673 |> Json.Codec.Object.opt_member "liked" uri_jsont ~enc:liked
630630- |> Json.Codec.Object.opt_member "streams" (Json.Codec.list uri_jsont) ~enc:streams
674674+ |> Json.Codec.Object.opt_member "streams"
675675+ (Json.Codec.list uri_jsont)
676676+ ~enc:streams
631677 |> Json.Codec.Object.opt_member "endpoints" Endpoints.jsont ~enc:endpoints
632678 |> Json.Codec.Object.opt_member "publicKey" Public_key.jsont ~enc:public_key
633633- |> Json.Codec.Object.opt_member "icon" (one_or_many Image_ref.jsont) ~enc:icon
634634- |> Json.Codec.Object.opt_member "image" (one_or_many Image_ref.jsont) ~enc:image
679679+ |> Json.Codec.Object.opt_member "icon"
680680+ (one_or_many Image_ref.jsont)
681681+ ~enc:icon
682682+ |> Json.Codec.Object.opt_member "image"
683683+ (one_or_many Image_ref.jsont)
684684+ ~enc:image
635685 |> Json.Codec.Object.opt_member "manuallyApprovesFollowers" Json.Codec.bool
636636- ~enc:manually_approves_followers
686686+ ~enc:manually_approves_followers
637687 |> Json.Codec.Object.opt_member "alsoKnownAs" (one_or_many uri_jsont)
638638- ~enc:also_known_as
639639- |> Json.Codec.Object.opt_member "discoverable" Json.Codec.bool ~enc:discoverable
688688+ ~enc:also_known_as
689689+ |> Json.Codec.Object.opt_member "discoverable" Json.Codec.bool
690690+ ~enc:discoverable
640691 |> Json.Codec.Object.opt_member "suspended" Json.Codec.bool ~enc:suspended
641692 |> Json.Codec.Object.opt_member "movedTo" uri_jsont ~enc:moved_to
642693 |> Json.Codec.Object.opt_member "featured" uri_jsont ~enc:featured
···646697647698(** Actor reference - can be URI or full Actor object. *)
648699module Actor_ref : sig
649649- type t =
650650- | Uri of Uri.t
651651- | Actor of Actor.t
700700+ type t = Uri of Uri.t | Actor of Actor.t
652701653702 val uri : Uri.t -> t
654703 val actor : Actor.t -> t
655704 val jsont : t Json.codec
656705end = struct
657657- type t =
658658- | Uri of Uri.t
659659- | Actor of Actor.t
706706+ type t = Uri of Uri.t | Actor of Actor.t
660707661708 let uri u = Uri u
662709 let actor a = Actor a
663710664711 let jsont =
665665- let dec_string = Json.Codec.map uri_jsont
712712+ let dec_string =
713713+ Json.Codec.map uri_jsont
666714 ~dec:(fun u -> Uri u)
667667- ~enc:(function Uri u -> u | Actor _ -> assert false) in
668668- let dec_object = Json.Codec.map Actor.jsont
715715+ ~enc:(function Uri u -> u | Actor _ -> assert false)
716716+ in
717717+ let dec_object =
718718+ Json.Codec.map Actor.jsont
669719 ~dec:(fun a -> Actor a)
670670- ~enc:(function Actor a -> a | Uri _ -> assert false) in
671671- Json.Codec.any ~kind:"Actor reference"
672672- ~dec_string ~dec_object
673673- ~enc:(function
674674- | Uri _ -> dec_string
675675- | Actor _ -> dec_object)
720720+ ~enc:(function Actor a -> a | Uri _ -> assert false)
721721+ in
722722+ Json.Codec.any ~kind:"Actor reference" ~dec_string ~dec_object
723723+ ~enc:(function Uri _ -> dec_string | Actor _ -> dec_object)
676724 ()
677725end
678726···746794 | _ -> None
747795748796 let jsont =
749749- Json.Codec.enum ~kind:"ObjectType" [
750750- "Note", Note;
751751- "Article", Article;
752752- "Page", Page;
753753- "Event", Event;
754754- "Image", Image;
755755- "Video", Video;
756756- "Audio", Audio;
757757- "Document", Document;
758758- "Place", Place;
759759- "Profile", Profile;
760760- "Tombstone", Tombstone;
761761- "Collection", Collection;
762762- "OrderedCollection", OrderedCollection;
763763- ]
797797+ Json.Codec.enum ~kind:"ObjectType"
798798+ [
799799+ ("Note", Note);
800800+ ("Article", Article);
801801+ ("Page", Page);
802802+ ("Event", Event);
803803+ ("Image", Image);
804804+ ("Video", Video);
805805+ ("Audio", Audio);
806806+ ("Document", Document);
807807+ ("Place", Place);
808808+ ("Profile", Profile);
809809+ ("Tombstone", Tombstone);
810810+ ("Collection", Collection);
811811+ ("OrderedCollection", OrderedCollection);
812812+ ]
764813end
765814766815(** {1 Object} *)
···802851 ?audience:Recipient.t list ->
803852 ?location:Link_or_uri.t ->
804853 ?preview:Link_or_uri.t ->
805805- unit -> t
854854+ unit ->
855855+ t
806856 (** Create a new Object. *)
807857808858 val context : t -> Context.t option
···836886 val audience : t -> Recipient.t list option
837887838888 val location : t -> Link_or_uri.t option
839839- (** [location t] returns the physical or logical location associated with the object. *)
889889+ (** [location t] returns the physical or logical location associated with the
890890+ object. *)
840891841892 val preview : t -> Link_or_uri.t option
842842- (** [preview t] returns a preview of the object, typically a smaller version. *)
893893+ (** [preview t] returns a preview of the object, typically a smaller version.
894894+ *)
843895844896 val jsont : t Json.codec
845897 (** JSON type for Objects. *)
···879931 }
880932881933 let make ?context ?id ~type_ ?name ?summary ?content ?media_type ?url
882882- ?attributed_to ?in_reply_to ?published ?updated ?deleted ?to_ ?cc
883883- ?bto ?bcc ?replies ?attachment ?tag ?generator ?icon ?image
884884- ?start_time ?end_time ?duration ?sensitive ?conversation ?audience
885885- ?location ?preview () =
886886- { context; id; type_; name; summary; content; media_type; url;
887887- attributed_to; in_reply_to; published; updated; deleted;
888888- to_; cc; bto; bcc; replies; attachment; tag; generator;
889889- icon; image; start_time; end_time; duration; sensitive;
890890- conversation; audience; location; preview }
934934+ ?attributed_to ?in_reply_to ?published ?updated ?deleted ?to_ ?cc ?bto
935935+ ?bcc ?replies ?attachment ?tag ?generator ?icon ?image ?start_time
936936+ ?end_time ?duration ?sensitive ?conversation ?audience ?location ?preview
937937+ () =
938938+ {
939939+ context;
940940+ id;
941941+ type_;
942942+ name;
943943+ summary;
944944+ content;
945945+ media_type;
946946+ url;
947947+ attributed_to;
948948+ in_reply_to;
949949+ published;
950950+ updated;
951951+ deleted;
952952+ to_;
953953+ cc;
954954+ bto;
955955+ bcc;
956956+ replies;
957957+ attachment;
958958+ tag;
959959+ generator;
960960+ icon;
961961+ image;
962962+ start_time;
963963+ end_time;
964964+ duration;
965965+ sensitive;
966966+ conversation;
967967+ audience;
968968+ location;
969969+ preview;
970970+ }
891971892972 let context t = t.context
893973 let id t = t.id
···92310039241004 let jsont =
9251005 Json.Codec.Object.map ~kind:"Object"
926926- (fun context id type_ name summary content media_type url attributed_to
927927- in_reply_to published updated deleted to_ cc bto bcc replies
928928- attachment tag generator icon image start_time end_time duration
929929- sensitive conversation audience location preview ->
930930- { context; id; type_; name; summary; content; media_type; url;
931931- attributed_to; in_reply_to; published; updated; deleted;
932932- to_; cc; bto; bcc; replies; attachment; tag; generator;
933933- icon; image; start_time; end_time; duration; sensitive;
934934- conversation; audience; location; preview })
10061006+ (fun
10071007+ context
10081008+ id
10091009+ type_
10101010+ name
10111011+ summary
10121012+ content
10131013+ media_type
10141014+ url
10151015+ attributed_to
10161016+ in_reply_to
10171017+ published
10181018+ updated
10191019+ deleted
10201020+ to_
10211021+ cc
10221022+ bto
10231023+ bcc
10241024+ replies
10251025+ attachment
10261026+ tag
10271027+ generator
10281028+ icon
10291029+ image
10301030+ start_time
10311031+ end_time
10321032+ duration
10331033+ sensitive
10341034+ conversation
10351035+ audience
10361036+ location
10371037+ preview
10381038+ ->
10391039+ {
10401040+ context;
10411041+ id;
10421042+ type_;
10431043+ name;
10441044+ summary;
10451045+ content;
10461046+ media_type;
10471047+ url;
10481048+ attributed_to;
10491049+ in_reply_to;
10501050+ published;
10511051+ updated;
10521052+ deleted;
10531053+ to_;
10541054+ cc;
10551055+ bto;
10561056+ bcc;
10571057+ replies;
10581058+ attachment;
10591059+ tag;
10601060+ generator;
10611061+ icon;
10621062+ image;
10631063+ start_time;
10641064+ end_time;
10651065+ duration;
10661066+ sensitive;
10671067+ conversation;
10681068+ audience;
10691069+ location;
10701070+ preview;
10711071+ })
9351072 |> Json.Codec.Object.opt_member "@context" Context.jsont ~enc:context
9361073 |> Json.Codec.Object.opt_member "id" uri_jsont ~enc:id
9371074 |> Json.Codec.Object.member "type" Object_type.jsont ~enc:type_
9381075 |> Json.Codec.Object.opt_member "name" Json.Codec.string ~enc:name
939939- |> Json.Codec.Object.member "summary" (nullable Json.Codec.string)
940940- ~dec_absent:None ~enc_omit:Option.is_none ~enc:summary
941941- |> Json.Codec.Object.member "content" (nullable Json.Codec.string)
942942- ~dec_absent:None ~enc_omit:Option.is_none ~enc:content
943943- |> Json.Codec.Object.opt_member "mediaType" Json.Codec.string ~enc:media_type
944944- |> Json.Codec.Object.opt_member "url" (one_or_many Link_or_uri.jsont) ~enc:url
945945- |> Json.Codec.Object.opt_member "attributedTo" Actor_ref.jsont ~enc:attributed_to
10761076+ |> Json.Codec.Object.member "summary"
10771077+ (nullable Json.Codec.string)
10781078+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:summary
10791079+ |> Json.Codec.Object.member "content"
10801080+ (nullable Json.Codec.string)
10811081+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:content
10821082+ |> Json.Codec.Object.opt_member "mediaType" Json.Codec.string
10831083+ ~enc:media_type
10841084+ |> Json.Codec.Object.opt_member "url"
10851085+ (one_or_many Link_or_uri.jsont)
10861086+ ~enc:url
10871087+ |> Json.Codec.Object.opt_member "attributedTo" Actor_ref.jsont
10881088+ ~enc:attributed_to
9461089 |> Json.Codec.Object.member "inReplyTo" (nullable uri_jsont)
947947- ~dec_absent:None ~enc_omit:Option.is_none ~enc:in_reply_to
10901090+ ~dec_absent:None ~enc_omit:Option.is_none ~enc:in_reply_to
9481091 |> Json.Codec.Object.opt_member "published" Datetime.jsont ~enc:published
9491092 |> Json.Codec.Object.opt_member "updated" Datetime.jsont ~enc:updated
9501093 |> Json.Codec.Object.opt_member "deleted" Datetime.jsont ~enc:deleted
951951- |> Json.Codec.Object.opt_member "to" (Json.Codec.list Recipient.jsont) ~enc:to_
952952- |> Json.Codec.Object.opt_member "cc" (Json.Codec.list Recipient.jsont) ~enc:cc
953953- |> Json.Codec.Object.opt_member "bto" (Json.Codec.list Recipient.jsont) ~enc:bto
954954- |> Json.Codec.Object.opt_member "bcc" (Json.Codec.list Recipient.jsont) ~enc:bcc
10941094+ |> Json.Codec.Object.opt_member "to"
10951095+ (Json.Codec.list Recipient.jsont)
10961096+ ~enc:to_
10971097+ |> Json.Codec.Object.opt_member "cc"
10981098+ (Json.Codec.list Recipient.jsont)
10991099+ ~enc:cc
11001100+ |> Json.Codec.Object.opt_member "bto"
11011101+ (Json.Codec.list Recipient.jsont)
11021102+ ~enc:bto
11031103+ |> Json.Codec.Object.opt_member "bcc"
11041104+ (Json.Codec.list Recipient.jsont)
11051105+ ~enc:bcc
9551106 |> Json.Codec.Object.opt_member "replies" uri_or_object_with_id ~enc:replies
956956- |> Json.Codec.Object.opt_member "attachment" (Json.Codec.list Link_or_uri.jsont)
957957- ~enc:attachment
958958- |> Json.Codec.Object.opt_member "tag" (Json.Codec.list Link_or_uri.jsont) ~enc:tag
11071107+ |> Json.Codec.Object.opt_member "attachment"
11081108+ (Json.Codec.list Link_or_uri.jsont)
11091109+ ~enc:attachment
11101110+ |> Json.Codec.Object.opt_member "tag"
11111111+ (Json.Codec.list Link_or_uri.jsont)
11121112+ ~enc:tag
9591113 |> Json.Codec.Object.opt_member "generator" uri_jsont ~enc:generator
960960- |> Json.Codec.Object.opt_member "icon" (one_or_many Image_ref.jsont) ~enc:icon
961961- |> Json.Codec.Object.opt_member "image" (one_or_many Image_ref.jsont) ~enc:image
11141114+ |> Json.Codec.Object.opt_member "icon"
11151115+ (one_or_many Image_ref.jsont)
11161116+ ~enc:icon
11171117+ |> Json.Codec.Object.opt_member "image"
11181118+ (one_or_many Image_ref.jsont)
11191119+ ~enc:image
9621120 |> Json.Codec.Object.opt_member "startTime" Datetime.jsont ~enc:start_time
9631121 |> Json.Codec.Object.opt_member "endTime" Datetime.jsont ~enc:end_time
9641122 |> Json.Codec.Object.opt_member "duration" Json.Codec.string ~enc:duration
9651123 |> Json.Codec.Object.opt_member "sensitive" Json.Codec.bool ~enc:sensitive
9661124 |> Json.Codec.Object.opt_member "conversation" uri_jsont ~enc:conversation
967967- |> Json.Codec.Object.opt_member "audience" (one_or_many Recipient.jsont) ~enc:audience
11251125+ |> Json.Codec.Object.opt_member "audience"
11261126+ (one_or_many Recipient.jsont)
11271127+ ~enc:audience
9681128 |> Json.Codec.Object.opt_member "location" Link_or_uri.jsont ~enc:location
9691129 |> Json.Codec.Object.opt_member "preview" Link_or_uri.jsont ~enc:preview
9701130 |> Json.Codec.Object.seal
···97211329731133(** Object reference - can be URI or full Object. *)
9741134module Object_ref : sig
975975- type t =
976976- | Uri of Uri.t
977977- | Object of Object.t
11351135+ type t = Uri of Uri.t | Object of Object.t
97811369791137 val uri : Uri.t -> t
9801138 val obj : Object.t -> t
9811139 val jsont : t Json.codec
9821140end = struct
983983- type t =
984984- | Uri of Uri.t
985985- | Object of Object.t
11411141+ type t = Uri of Uri.t | Object of Object.t
98611429871143 let uri u = Uri u
9881144 let obj o = Object o
98911459901146 let jsont =
991991- let dec_string = Json.Codec.map uri_jsont
11471147+ let dec_string =
11481148+ Json.Codec.map uri_jsont
9921149 ~dec:(fun u -> Uri u)
993993- ~enc:(function Uri u -> u | Object _ -> assert false) in
994994- let dec_object = Json.Codec.map Object.jsont
11501150+ ~enc:(function Uri u -> u | Object _ -> assert false)
11511151+ in
11521152+ let dec_object =
11531153+ Json.Codec.map Object.jsont
9951154 ~dec:(fun o -> Object o)
996996- ~enc:(function Object o -> o | Uri _ -> assert false) in
997997- Json.Codec.any ~kind:"Object reference"
998998- ~dec_string ~dec_object
999999- ~enc:(function
10001000- | Uri _ -> dec_string
10011001- | Object _ -> dec_object)
11551155+ ~enc:(function Object o -> o | Uri _ -> assert false)
11561156+ in
11571157+ Json.Codec.any ~kind:"Object reference" ~dec_string ~dec_object
11581158+ ~enc:(function Uri _ -> dec_string | Object _ -> dec_object)
10021159 ()
10031160end
10041161···11281285 | _ -> None
1129128611301287 let jsont =
11311131- Json.Codec.enum ~kind:"ActivityType" [
11321132- "Create", Create;
11331133- "Update", Update;
11341134- "Delete", Delete;
11351135- "Follow", Follow;
11361136- "Accept", Accept;
11371137- "Reject", Reject;
11381138- "Add", Add;
11391139- "Remove", Remove;
11401140- "Like", Like;
11411141- "Announce", Announce;
11421142- "Undo", Undo;
11431143- "Block", Block;
11441144- "Flag", Flag;
11451145- "Dislike", Dislike;
11461146- "Ignore", Ignore;
11471147- "Invite", Invite;
11481148- "Join", Join;
11491149- "Leave", Leave;
11501150- "Listen", Listen;
11511151- "Move", Move;
11521152- "Offer", Offer;
11531153- "Question", Question;
11541154- "Read", Read;
11551155- "TentativeAccept", TentativeAccept;
11561156- "TentativeReject", TentativeReject;
11571157- "Travel", Travel;
11581158- "View", View;
11591159- ]
12881288+ Json.Codec.enum ~kind:"ActivityType"
12891289+ [
12901290+ ("Create", Create);
12911291+ ("Update", Update);
12921292+ ("Delete", Delete);
12931293+ ("Follow", Follow);
12941294+ ("Accept", Accept);
12951295+ ("Reject", Reject);
12961296+ ("Add", Add);
12971297+ ("Remove", Remove);
12981298+ ("Like", Like);
12991299+ ("Announce", Announce);
13001300+ ("Undo", Undo);
13011301+ ("Block", Block);
13021302+ ("Flag", Flag);
13031303+ ("Dislike", Dislike);
13041304+ ("Ignore", Ignore);
13051305+ ("Invite", Invite);
13061306+ ("Join", Join);
13071307+ ("Leave", Leave);
13081308+ ("Listen", Listen);
13091309+ ("Move", Move);
13101310+ ("Offer", Offer);
13111311+ ("Question", Question);
13121312+ ("Read", Read);
13131313+ ("TentativeAccept", TentativeAccept);
13141314+ ("TentativeReject", TentativeReject);
13151315+ ("Travel", Travel);
13161316+ ("View", View);
13171317+ ]
11601318end
1161131911621320(** {1 Activity} *)
···11861344 ?one_of:Object_ref.t list ->
11871345 ?any_of:Object_ref.t list ->
11881346 ?closed:Datetime.t ->
11891189- unit -> t
13471347+ unit ->
13481348+ t
11901349 (** Create a new Activity.
1191135011921351 The [one_of], [any_of], and [closed] fields are only used for Question
11931193- activities (polls). Use [one_of] for single-choice polls and [any_of]
11941194- for multiple-choice polls. *)
13521352+ activities (polls). Use [one_of] for single-choice polls and [any_of] for
13531353+ multiple-choice polls. *)
1195135411961355 val context : t -> Context.t option
11971356 val id : t -> Uri.t option
···12141373 (** [one_of t] returns single-choice poll options for Question activities. *)
1215137412161375 val any_of : t -> Object_ref.t list option
12171217- (** [any_of t] returns multiple-choice poll options for Question activities. *)
13761376+ (** [any_of t] returns multiple-choice poll options for Question activities.
13771377+ *)
1218137812191379 val closed : t -> Datetime.t option
12201380 (** [closed t] returns when the poll was closed, for Question activities. *)
···12451405 }
1246140612471407 let make ?context ?id ~type_ ~actor ?object_ ?target ?result ?origin
12481248- ?instrument ?to_ ?cc ?bto ?bcc ?published ?updated ?summary
12491249- ?one_of ?any_of ?closed () =
12501250- { context; id; type_; actor; object_; target; result; origin;
12511251- instrument; to_; cc; bto; bcc; published; updated; summary;
12521252- one_of; any_of; closed }
14081408+ ?instrument ?to_ ?cc ?bto ?bcc ?published ?updated ?summary ?one_of
14091409+ ?any_of ?closed () =
14101410+ {
14111411+ context;
14121412+ id;
14131413+ type_;
14141414+ actor;
14151415+ object_;
14161416+ target;
14171417+ result;
14181418+ origin;
14191419+ instrument;
14201420+ to_;
14211421+ cc;
14221422+ bto;
14231423+ bcc;
14241424+ published;
14251425+ updated;
14261426+ summary;
14271427+ one_of;
14281428+ any_of;
14291429+ closed;
14301430+ }
1253143112541432 let context t = t.context
12551433 let id t = t.id
···1273145112741452 let jsont =
12751453 Json.Codec.Object.map ~kind:"Activity"
12761276- (fun context id type_ actor object_ target result origin instrument
12771277- to_ cc bto bcc published updated summary one_of any_of closed ->
12781278- { context; id; type_; actor; object_; target; result; origin;
12791279- instrument; to_; cc; bto; bcc; published; updated; summary;
12801280- one_of; any_of; closed })
14541454+ (fun
14551455+ context
14561456+ id
14571457+ type_
14581458+ actor
14591459+ object_
14601460+ target
14611461+ result
14621462+ origin
14631463+ instrument
14641464+ to_
14651465+ cc
14661466+ bto
14671467+ bcc
14681468+ published
14691469+ updated
14701470+ summary
14711471+ one_of
14721472+ any_of
14731473+ closed
14741474+ ->
14751475+ {
14761476+ context;
14771477+ id;
14781478+ type_;
14791479+ actor;
14801480+ object_;
14811481+ target;
14821482+ result;
14831483+ origin;
14841484+ instrument;
14851485+ to_;
14861486+ cc;
14871487+ bto;
14881488+ bcc;
14891489+ published;
14901490+ updated;
14911491+ summary;
14921492+ one_of;
14931493+ any_of;
14941494+ closed;
14951495+ })
12811496 |> Json.Codec.Object.opt_member "@context" Context.jsont ~enc:context
12821497 |> Json.Codec.Object.opt_member "id" uri_jsont ~enc:id
12831498 |> Json.Codec.Object.member "type" Activity_type.jsont ~enc:type_
···12861501 |> Json.Codec.Object.opt_member "target" Object_ref.jsont ~enc:target
12871502 |> Json.Codec.Object.opt_member "result" Object_ref.jsont ~enc:result
12881503 |> Json.Codec.Object.opt_member "origin" Object_ref.jsont ~enc:origin
12891289- |> Json.Codec.Object.opt_member "instrument" Object_ref.jsont ~enc:instrument
12901290- |> Json.Codec.Object.opt_member "to" (Json.Codec.list Recipient.jsont) ~enc:to_
12911291- |> Json.Codec.Object.opt_member "cc" (Json.Codec.list Recipient.jsont) ~enc:cc
12921292- |> Json.Codec.Object.opt_member "bto" (Json.Codec.list Recipient.jsont) ~enc:bto
12931293- |> Json.Codec.Object.opt_member "bcc" (Json.Codec.list Recipient.jsont) ~enc:bcc
15041504+ |> Json.Codec.Object.opt_member "instrument" Object_ref.jsont
15051505+ ~enc:instrument
15061506+ |> Json.Codec.Object.opt_member "to"
15071507+ (Json.Codec.list Recipient.jsont)
15081508+ ~enc:to_
15091509+ |> Json.Codec.Object.opt_member "cc"
15101510+ (Json.Codec.list Recipient.jsont)
15111511+ ~enc:cc
15121512+ |> Json.Codec.Object.opt_member "bto"
15131513+ (Json.Codec.list Recipient.jsont)
15141514+ ~enc:bto
15151515+ |> Json.Codec.Object.opt_member "bcc"
15161516+ (Json.Codec.list Recipient.jsont)
15171517+ ~enc:bcc
12941518 |> Json.Codec.Object.opt_member "published" Datetime.jsont ~enc:published
12951519 |> Json.Codec.Object.opt_member "updated" Datetime.jsont ~enc:updated
12961520 |> Json.Codec.Object.opt_member "summary" Json.Codec.string ~enc:summary
12971297- |> Json.Codec.Object.opt_member "oneOf" (Json.Codec.list Object_ref.jsont) ~enc:one_of
12981298- |> Json.Codec.Object.opt_member "anyOf" (Json.Codec.list Object_ref.jsont) ~enc:any_of
15211521+ |> Json.Codec.Object.opt_member "oneOf"
15221522+ (Json.Codec.list Object_ref.jsont)
15231523+ ~enc:one_of
15241524+ |> Json.Codec.Object.opt_member "anyOf"
15251525+ (Json.Codec.list Object_ref.jsont)
15261526+ ~enc:any_of
12991527 |> Json.Codec.Object.opt_member "closed" Datetime.jsont ~enc:closed
13001528 |> Json.Codec.Object.seal
13011529end
1302153013031531(** Activity reference - can be URI or full Activity. *)
13041532module Activity_ref : sig
13051305- type t =
13061306- | Uri of Uri.t
13071307- | Activity of Activity.t
15331533+ type t = Uri of Uri.t | Activity of Activity.t
1308153413091535 val uri : Uri.t -> t
13101536 val activity : Activity.t -> t
13111537 val jsont : t Json.codec
13121538end = struct
13131313- type t =
13141314- | Uri of Uri.t
13151315- | Activity of Activity.t
15391539+ type t = Uri of Uri.t | Activity of Activity.t
1316154013171541 let uri u = Uri u
13181542 let activity a = Activity a
1319154313201544 let jsont =
13211321- let dec_string = Json.Codec.map uri_jsont
15451545+ let dec_string =
15461546+ Json.Codec.map uri_jsont
13221547 ~dec:(fun u -> Uri u)
13231323- ~enc:(function Uri u -> u | Activity _ -> assert false) in
13241324- let dec_object = Json.Codec.map Activity.jsont
15481548+ ~enc:(function Uri u -> u | Activity _ -> assert false)
15491549+ in
15501550+ let dec_object =
15511551+ Json.Codec.map Activity.jsont
13251552 ~dec:(fun a -> Activity a)
13261326- ~enc:(function Activity a -> a | Uri _ -> assert false) in
13271327- Json.Codec.any ~kind:"Activity reference"
13281328- ~dec_string ~dec_object
13291329- ~enc:(function
13301330- | Uri _ -> dec_string
13311331- | Activity _ -> dec_object)
15531553+ ~enc:(function Activity a -> a | Uri _ -> assert false)
15541554+ in
15551555+ Json.Codec.any ~kind:"Activity reference" ~dec_string ~dec_object
15561556+ ~enc:(function Uri _ -> dec_string | Activity _ -> dec_object)
13321557 ()
13331558end
13341559···13481573 ?last:Uri.t ->
13491574 ?items:'a list ->
13501575 ordered:bool ->
13511351- unit -> 'a t
15761576+ unit ->
15771577+ 'a t
1352157813531579 val context : 'a t -> Context.t option
13541580 val id : 'a t -> Uri.t option
···13581584 val last : 'a t -> Uri.t option
13591585 val items : 'a t -> 'a list option
13601586 val ordered : 'a t -> bool
13611361-13621587 val jsont : 'a Json.codec -> 'a t Json.codec
13631588end = struct
13641589 type 'a t = {
···1386161113871612 let jsont item_jsont =
13881613 let type_jsont =
13891389- Json.Codec.enum ~kind:"CollectionType" [
13901390- "Collection", false;
13911391- "OrderedCollection", true;
13921392- ]
16141614+ Json.Codec.enum ~kind:"CollectionType"
16151615+ [ ("Collection", false); ("OrderedCollection", true) ]
13931616 in
13941617 let list_jsont = Json.Codec.list item_jsont in
13951618 Json.Codec.Object.map ~kind:"Collection"
13961396- (fun context id ordered total_items current first last items ordered_items ->
13971397- let items = match items, ordered_items with
13981398- | Some i, _ -> Some i
13991399- | None, Some i -> Some i
14001400- | None, None -> None
14011401- in
14021402- { context; id; total_items; current; first; last; items; ordered })
16191619+ (fun
16201620+ context id ordered total_items current first last items ordered_items ->
16211621+ let items =
16221622+ match (items, ordered_items) with
16231623+ | Some i, _ -> Some i
16241624+ | None, Some i -> Some i
16251625+ | None, None -> None
16261626+ in
16271627+ { context; id; total_items; current; first; last; items; ordered })
14031628 |> Json.Codec.Object.opt_member "@context" Context.jsont ~enc:context
14041629 |> Json.Codec.Object.opt_member "id" uri_jsont ~enc:id
14051630 |> Json.Codec.Object.member "type" type_jsont ~enc:ordered
···14071632 |> Json.Codec.Object.opt_member "current" uri_jsont ~enc:current
14081633 |> Json.Codec.Object.opt_member "first" uri_jsont ~enc:first
14091634 |> Json.Codec.Object.opt_member "last" uri_jsont ~enc:last
14101410- |> Json.Codec.Object.opt_member "items" list_jsont
14111411- ~enc:(fun t -> if t.ordered then None else t.items)
14121412- |> Json.Codec.Object.opt_member "orderedItems" list_jsont
14131413- ~enc:(fun t -> if t.ordered then t.items else None)
16351635+ |> Json.Codec.Object.opt_member "items" list_jsont ~enc:(fun t ->
16361636+ if t.ordered then None else t.items)
16371637+ |> Json.Codec.Object.opt_member "orderedItems" list_jsont ~enc:(fun t ->
16381638+ if t.ordered then t.items else None)
14141639 |> Json.Codec.Object.seal
14151640end
1416164114171642(** {1 Collection Page} *)
1418164314191644(** Collection page objects.
14201420- @see <https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage> *)
16451645+ @see <https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage>
16461646+*)
14211647module Collection_page : sig
14221648 type 'a t
14231649···14331659 ?part_of:Uri.t ->
14341660 ?items:'a list ->
14351661 ordered:bool ->
14361436- unit -> 'a t
16621662+ unit ->
16631663+ 'a t
1437166414381665 val context : 'a t -> Context.t option
14391666 val id : 'a t -> Uri.t option
···14461673 val part_of : 'a t -> Uri.t option
14471674 val items : 'a t -> 'a list option
14481675 val ordered : 'a t -> bool
14491449-14501676 val jsont : 'a Json.codec -> 'a t Json.codec
14511677end = struct
14521678 type 'a t = {
···14631689 ordered : bool;
14641690 }
1465169114661466- let make ?context ?id ?total_items ?current ?first ?last ?prev ?next
14671467- ?part_of ?items ~ordered () =
14681468- { context; id; total_items; current; first; last; prev; next;
14691469- part_of; items; ordered }
16921692+ let make ?context ?id ?total_items ?current ?first ?last ?prev ?next ?part_of
16931693+ ?items ~ordered () =
16941694+ {
16951695+ context;
16961696+ id;
16971697+ total_items;
16981698+ current;
16991699+ first;
17001700+ last;
17011701+ prev;
17021702+ next;
17031703+ part_of;
17041704+ items;
17051705+ ordered;
17061706+ }
1470170714711708 let context t = t.context
14721709 let id t = t.id
···1482171914831720 let jsont item_jsont =
14841721 let type_jsont =
14851485- Json.Codec.enum ~kind:"CollectionPageType" [
14861486- "CollectionPage", false;
14871487- "OrderedCollectionPage", true;
14881488- ]
17221722+ Json.Codec.enum ~kind:"CollectionPageType"
17231723+ [ ("CollectionPage", false); ("OrderedCollectionPage", true) ]
14891724 in
14901725 let list_jsont = Json.Codec.list item_jsont in
14911726 Json.Codec.Object.map ~kind:"CollectionPage"
14921492- (fun context id ordered total_items current first last prev next
14931493- part_of items ordered_items ->
14941494- let items = match items, ordered_items with
17271727+ (fun
17281728+ context
17291729+ id
17301730+ ordered
17311731+ total_items
17321732+ current
17331733+ first
17341734+ last
17351735+ prev
17361736+ next
17371737+ part_of
17381738+ items
17391739+ ordered_items
17401740+ ->
17411741+ let items =
17421742+ match (items, ordered_items) with
14951743 | Some i, _ -> Some i
14961744 | None, Some i -> Some i
14971745 | None, None -> None
14981746 in
14991499- { context; id; total_items; current; first; last; prev; next;
15001500- part_of; items; ordered })
17471747+ {
17481748+ context;
17491749+ id;
17501750+ total_items;
17511751+ current;
17521752+ first;
17531753+ last;
17541754+ prev;
17551755+ next;
17561756+ part_of;
17571757+ items;
17581758+ ordered;
17591759+ })
15011760 |> Json.Codec.Object.opt_member "@context" Context.jsont ~enc:context
15021761 |> Json.Codec.Object.opt_member "id" uri_jsont ~enc:id
15031762 |> Json.Codec.Object.member "type" type_jsont ~enc:ordered
···15081767 |> Json.Codec.Object.opt_member "prev" uri_jsont ~enc:prev
15091768 |> Json.Codec.Object.opt_member "next" uri_jsont ~enc:next
15101769 |> Json.Codec.Object.opt_member "partOf" uri_jsont ~enc:part_of
15111511- |> Json.Codec.Object.opt_member "items" list_jsont
15121512- ~enc:(fun t -> if t.ordered then None else t.items)
15131513- |> Json.Codec.Object.opt_member "orderedItems" list_jsont
15141514- ~enc:(fun t -> if t.ordered then t.items else None)
17701770+ |> Json.Codec.Object.opt_member "items" list_jsont ~enc:(fun t ->
17711771+ if t.ordered then None else t.items)
17721772+ |> Json.Codec.Object.opt_member "orderedItems" list_jsont ~enc:(fun t ->
17731773+ if t.ordered then t.items else None)
15151774 |> Json.Codec.Object.seal
15161775end
15171776···15201779(** Activity collection. *)
15211780module Activity_collection : sig
15221781 type t = Activity.t Collection.t
17821782+15231783 val jsont : t Json.codec
15241784end = struct
15251785 type t = Activity.t Collection.t
17861786+15261787 let jsont = Collection.jsont Activity.jsont
15271788end
1528178915291790(** Object collection. *)
15301791module Object_collection : sig
15311792 type t = Object.t Collection.t
17931793+15321794 val jsont : t Json.codec
15331795end = struct
15341796 type t = Object.t Collection.t
17971797+15351798 let jsont = Collection.jsont Object.jsont
15361799end
1537180015381801(** Activity collection page. *)
15391802module Activity_collection_page : sig
15401803 type t = Activity.t Collection_page.t
18041804+15411805 val jsont : t Json.codec
15421806end = struct
15431807 type t = Activity.t Collection_page.t
18081808+15441809 let jsont = Collection_page.jsont Activity.jsont
15451810end
1546181115471812(** Object collection page. *)
15481813module Object_collection_page : sig
15491814 type t = Object.t Collection_page.t
18151815+15501816 val jsont : t Json.codec
15511817end = struct
15521818 type t = Object.t Collection_page.t
18191819+15531820 let jsont = Collection_page.jsont Object.jsont
15541821end
15551822···15671834 ?type_:string ->
15681835 ?href:Uri.t ->
15691836 ?template:string ->
15701570- unit -> t
18371837+ unit ->
18381838+ t
1571183915721840 val rel : t -> string
15731841 val type_ : t -> string option
15741842 val href : t -> Uri.t option
15751843 val template : t -> string option
15761576-15771844 val jsont : t Json.codec
15781845 end
1579184615801580- (** The Webfinger JRD response. *)
15811847 type t
18481848+ (** The Webfinger JRD response. *)
1582184915831850 val make :
15841851 subject:string ->
15851852 ?aliases:string list ->
15861853 ?properties:(string * string) list ->
15871854 ?links:Jrd_link.t list ->
15881588- unit -> t
18551855+ unit ->
18561856+ t
1589185715901858 val subject : t -> string
15911859 val aliases : t -> string list option
15921860 val properties : t -> (string * string) list option
15931861 val links : t -> Jrd_link.t list option
15941594-15951862 val jsont : t Json.codec
15961863end = struct
15971864 module Jrd_link = struct
···16021869 template : string option;
16031870 }
1604187116051605- let make ~rel ?type_ ?href ?template () =
16061606- { rel; type_; href; template }
16071607-18721872+ let make ~rel ?type_ ?href ?template () = { rel; type_; href; template }
16081873 let rel t = t.rel
16091874 let type_ t = t.type_
16101875 let href t = t.href
16111876 let template t = t.template
1612187716131878 let jsont =
16141614- Json.Codec.Object.map ~kind:"JrdLink"
16151615- (fun rel type_ href template -> { rel; type_; href; template })
18791879+ Json.Codec.Object.map ~kind:"JrdLink" (fun rel type_ href template ->
18801880+ { rel; type_; href; template })
16161881 |> Json.Codec.Object.member "rel" Json.Codec.string ~enc:rel
16171882 |> Json.Codec.Object.opt_member "type" Json.Codec.string ~enc:type_
16181883 |> Json.Codec.Object.opt_member "href" uri_jsont ~enc:href
···16351900 let properties t = t.properties
16361901 let links t = t.links
1637190216381638- module String_map = Map.Make(String)
19031903+ module String_map = Map.Make (String)
1639190416401905 let properties_jsont =
16411906 Json.Codec.Object.as_string_map Json.Codec.string
16421907 |> Json.Codec.map
16431643- ~dec:(fun m -> String_map.bindings m)
16441644- ~enc:(fun l -> List.fold_left (fun m (k, v) ->
16451645- String_map.add k v m) String_map.empty l)
19081908+ ~dec:(fun m -> String_map.bindings m)
19091909+ ~enc:(fun l ->
19101910+ List.fold_left
19111911+ (fun m (k, v) -> String_map.add k v m)
19121912+ String_map.empty l)
1646191316471914 let jsont =
16481915 Json.Codec.Object.map ~kind:"Webfinger"
16491916 (fun subject aliases properties links ->
16501650- { subject; aliases; properties; links })
19171917+ { subject; aliases; properties; links })
16511918 |> Json.Codec.Object.member "subject" Json.Codec.string ~enc:subject
16521652- |> Json.Codec.Object.opt_member "aliases" (Json.Codec.list Json.Codec.string) ~enc:aliases
16531653- |> Json.Codec.Object.opt_member "properties" properties_jsont ~enc:properties
16541654- |> Json.Codec.Object.opt_member "links" (Json.Codec.list Jrd_link.jsont) ~enc:links
19191919+ |> Json.Codec.Object.opt_member "aliases"
19201920+ (Json.Codec.list Json.Codec.string)
19211921+ ~enc:aliases
19221922+ |> Json.Codec.Object.opt_member "properties" properties_jsont
19231923+ ~enc:properties
19241924+ |> Json.Codec.Object.opt_member "links"
19251925+ (Json.Codec.list Jrd_link.jsont)
19261926+ ~enc:links
16551927 |> Json.Codec.Object.seal
16561928end
16571929···16691941 version:string ->
16701942 ?repository:Uri.t ->
16711943 ?homepage:Uri.t ->
16721672- unit -> t
19441944+ unit ->
19451945+ t
1673194616741947 val name : t -> string
16751948 val version : t -> string
16761949 val repository : t -> Uri.t option
16771950 val homepage : t -> Uri.t option
16781678-16791951 val jsont : t Json.codec
16801952 end
16811953···16891961 ?users_active_month:int ->
16901962 ?local_posts:int ->
16911963 ?local_comments:int ->
16921692- unit -> t
19641964+ unit ->
19651965+ t
1693196616941967 val users_total : t -> int option
16951968 val users_active_half_year : t -> int option
16961969 val users_active_month : t -> int option
16971970 val local_posts : t -> int option
16981971 val local_comments : t -> int option
16991699-17001972 val jsont : t Json.codec
17011973 end
17021974···17091981 usage:Usage.t ->
17101982 open_registrations:bool ->
17111983 ?metadata:Json.t ->
17121712- unit -> t
19841984+ unit ->
19851985+ t
1713198617141987 val version : t -> string
17151988 val software : t -> Software.t
···17171990 val usage : t -> Usage.t
17181991 val open_registrations : t -> bool
17191992 val metadata : t -> Json.t option
17201720-17211993 val jsont : t Json.codec
17221994end = struct
17231995 module Software = struct
···17392011 let jsont =
17402012 Json.Codec.Object.map ~kind:"Software"
17412013 (fun name version repository homepage ->
17421742- { name; version; repository; homepage })
20142014+ { name; version; repository; homepage })
17432015 |> Json.Codec.Object.member "name" Json.Codec.string ~enc:name
17442016 |> Json.Codec.Object.member "version" Json.Codec.string ~enc:version
17452017 |> Json.Codec.Object.opt_member "repository" uri_jsont ~enc:repository
···1758203017592031 let make ?users_total ?users_active_half_year ?users_active_month
17602032 ?local_posts ?local_comments () =
17611761- { users_total; users_active_half_year; users_active_month;
17621762- local_posts; local_comments }
20332033+ {
20342034+ users_total;
20352035+ users_active_half_year;
20362036+ users_active_month;
20372037+ local_posts;
20382038+ local_comments;
20392039+ }
1763204017642041 let users_total t = t.users_total
17652042 let users_active_half_year t = t.users_active_half_year
···17702047 let users_jsont =
17712048 Json.Codec.Object.map ~kind:"Users"
17722049 (fun total active_half_year active_month ->
17731773- (total, active_half_year, active_month))
20502050+ (total, active_half_year, active_month))
17742051 |> Json.Codec.Object.opt_member "total" Json.Codec.int
17751775- ~enc:(fun (t, _, _) -> t)
20522052+ ~enc:(fun (t, _, _) -> t)
17762053 |> Json.Codec.Object.opt_member "activeHalfyear" Json.Codec.int
17771777- ~enc:(fun (_, h, _) -> h)
20542054+ ~enc:(fun (_, h, _) -> h)
17782055 |> Json.Codec.Object.opt_member "activeMonth" Json.Codec.int
17791779- ~enc:(fun (_, _, m) -> m)
20562056+ ~enc:(fun (_, _, m) -> m)
17802057 |> Json.Codec.Object.seal
1781205817822059 let jsont =
17832060 Json.Codec.Object.map ~kind:"Usage"
17841784- (fun (users_total, users_active_half_year, users_active_month)
17851785- local_posts local_comments ->
17861786- { users_total; users_active_half_year; users_active_month;
17871787- local_posts; local_comments })
20612061+ (fun
20622062+ (users_total, users_active_half_year, users_active_month)
20632063+ local_posts
20642064+ local_comments
20652065+ ->
20662066+ {
20672067+ users_total;
20682068+ users_active_half_year;
20692069+ users_active_month;
20702070+ local_posts;
20712071+ local_comments;
20722072+ })
17882073 |> Json.Codec.Object.member "users" users_jsont
17891789- ~dec_absent:(None, None, None)
17901790- ~enc:(fun t -> (t.users_total, t.users_active_half_year,
17911791- t.users_active_month))
17921792- |> Json.Codec.Object.opt_member "localPosts" Json.Codec.int ~enc:local_posts
17931793- |> Json.Codec.Object.opt_member "localComments" Json.Codec.int ~enc:local_comments
20742074+ ~dec_absent:(None, None, None) ~enc:(fun t ->
20752075+ (t.users_total, t.users_active_half_year, t.users_active_month))
20762076+ |> Json.Codec.Object.opt_member "localPosts" Json.Codec.int
20772077+ ~enc:local_posts
20782078+ |> Json.Codec.Object.opt_member "localComments" Json.Codec.int
20792079+ ~enc:local_comments
17942080 |> Json.Codec.Object.seal
17952081 end
17962082···18032089 metadata : Json.t option;
18042090 }
1805209118061806- let make ~version ~software ~protocols ~usage ~open_registrations
18071807- ?metadata () =
20922092+ let make ~version ~software ~protocols ~usage ~open_registrations ?metadata ()
20932093+ =
18082094 { version; software; protocols; usage; open_registrations; metadata }
1809209518102096 let version t = t.version
···18172103 let jsont =
18182104 Json.Codec.Object.map ~kind:"Nodeinfo"
18192105 (fun version software protocols usage open_registrations metadata ->
18201820- { version; software; protocols; usage; open_registrations; metadata })
21062106+ { version; software; protocols; usage; open_registrations; metadata })
18212107 |> Json.Codec.Object.member "version" Json.Codec.string ~enc:version
18222108 |> Json.Codec.Object.member "software" Software.jsont ~enc:software
18231823- |> Json.Codec.Object.member "protocols" (Json.Codec.list Json.Codec.string) ~enc:protocols
21092109+ |> Json.Codec.Object.member "protocols"
21102110+ (Json.Codec.list Json.Codec.string)
21112111+ ~enc:protocols
18242112 |> Json.Codec.Object.member "usage" Usage.jsont ~enc:usage
18251825- |> Json.Codec.Object.member "openRegistrations" Json.Codec.bool ~enc:open_registrations
21132113+ |> Json.Codec.Object.member "openRegistrations" Json.Codec.bool
21142114+ ~enc:open_registrations
18262115 |> Json.Codec.Object.opt_member "metadata" Json.Codec.Value.t ~enc:metadata
18272116 |> Json.Codec.Object.seal
18282117end
+51-57
lib/proto/apubt_proto.mli
···21212222 @see <https://www.w3.org/TR/activitypub/> ActivityPub specification
2323 @see <https://www.w3.org/TR/activitystreams-core/> ActivityStreams Core
2424- @see <https://www.w3.org/TR/activitystreams-vocabulary/> ActivityStreams Vocabulary *)
2424+ @see <https://www.w3.org/TR/activitystreams-vocabulary/>
2525+ ActivityStreams Vocabulary *)
25262627(** {1 Common Types} *)
2728···6869 ?width:int ->
6970 ?preview:Uri.t ->
7071 href:Uri.t ->
7171- unit -> t
7272+ unit ->
7373+ t
7274 (** Create a new Link. *)
73757476 val href : t -> Uri.t
···85878688(** Reference that can be either a URI string or a Link object. *)
8789module Link_or_uri : sig
8888- type t =
8989- | Uri of Uri.t
9090- | Link of Link.t
9090+ type t = Uri of Uri.t | Link of Link.t
91919292 val uri : Uri.t -> t
9393 val link : Link.t -> t
···108108 ?width:int ->
109109 ?height:int ->
110110 url:Link_or_uri.t ->
111111- unit -> t
111111+ unit ->
112112+ t
112113113114 val id : t -> Uri.t option
114115 val url : t -> Link_or_uri.t
···116117 val media_type : t -> string option
117118 val width : t -> int option
118119 val height : t -> int option
119119-120120 val jsont : t Json.codec
121121end
122122123123(** Image reference - can be URI, Link, or full Image object. *)
124124module Image_ref : sig
125125- type t =
126126- | Uri of Uri.t
127127- | Link of Link.t
128128- | Image of Image.t
125125+ type t = Uri of Uri.t | Link of Link.t | Image of Image.t
129126130127 val uri : Uri.t -> t
131128 val link : Link.t -> t
···166163 ?provide_client_key:Uri.t ->
167164 ?sign_client_key:Uri.t ->
168165 ?shared_inbox:Uri.t ->
169169- unit -> t
166166+ unit ->
167167+ t
170168171169 val proxy_url : t -> Uri.t option
172170 val oauth_authorization_endpoint : t -> Uri.t option
···174172 val provide_client_key : t -> Uri.t option
175173 val sign_client_key : t -> Uri.t option
176174 val shared_inbox : t -> Uri.t option
177177-178175 val jsont : t Json.codec
179176end
180177···184181module Public_key : sig
185182 type t
186183187187- val make :
188188- id:Uri.t ->
189189- owner:Uri.t ->
190190- public_key_pem:string ->
191191- unit -> t
192192-184184+ val make : id:Uri.t -> owner:Uri.t -> public_key_pem:string -> unit -> t
193185 val id : t -> Uri.t
194186 val owner : t -> Uri.t
195187 val public_key_pem : t -> string
196196-197188 val jsont : t Json.codec
198189end
199190···201192202193(** Actor types enumeration. *)
203194module Actor_type : sig
204204- type t =
205205- | Person
206206- | Service
207207- | Organization
208208- | Group
209209- | Application
195195+ type t = Person | Service | Organization | Group | Application
210196211197 val to_string : t -> string
212198 val of_string : string -> t option
···245231 ?moved_to:Uri.t ->
246232 ?featured:Uri.t ->
247233 ?featured_tags:Uri.t ->
248248- unit -> t
234234+ unit ->
235235+ t
249236 (** Create a new Actor. *)
250237251238 val context : t -> Context.t option
···279266280267(** Actor reference - can be URI or full Actor object. *)
281268module Actor_ref : sig
282282- type t =
283283- | Uri of Uri.t
284284- | Actor of Actor.t
269269+ type t = Uri of Uri.t | Actor of Actor.t
285270286271 val uri : Uri.t -> t
287272 val actor : Actor.t -> t
···351336 ?audience:Recipient.t list ->
352337 ?location:Link_or_uri.t ->
353338 ?preview:Link_or_uri.t ->
354354- unit -> t
339339+ unit ->
340340+ t
355341 (** Create a new Object. *)
356342357343 val context : t -> Context.t option
···385371 val audience : t -> Recipient.t list option
386372387373 val location : t -> Link_or_uri.t option
388388- (** [location t] returns the physical or logical location associated with the object. *)
374374+ (** [location t] returns the physical or logical location associated with the
375375+ object. *)
389376390377 val preview : t -> Link_or_uri.t option
391391- (** [preview t] returns a preview of the object, typically a smaller version. *)
378378+ (** [preview t] returns a preview of the object, typically a smaller version.
379379+ *)
392380393381 val jsont : t Json.codec
394382 (** JSON type for Objects. *)
···396384397385(** Object reference - can be URI or full Object. *)
398386module Object_ref : sig
399399- type t =
400400- | Uri of Uri.t
401401- | Object of Object.t
387387+ type t = Uri of Uri.t | Object of Object.t
402388403389 val uri : Uri.t -> t
404390 val obj : Object.t -> t
···470456 ?one_of:Object_ref.t list ->
471457 ?any_of:Object_ref.t list ->
472458 ?closed:Datetime.t ->
473473- unit -> t
459459+ unit ->
460460+ t
474461 (** Create a new Activity.
475462476463 The [one_of], [any_of], and [closed] fields are only used for Question
477477- activities (polls). Use [one_of] for single-choice polls and [any_of]
478478- for multiple-choice polls. *)
464464+ activities (polls). Use [one_of] for single-choice polls and [any_of] for
465465+ multiple-choice polls. *)
479466480467 val context : t -> Context.t option
481468 val id : t -> Uri.t option
···498485 (** [one_of t] returns single-choice poll options for Question activities. *)
499486500487 val any_of : t -> Object_ref.t list option
501501- (** [any_of t] returns multiple-choice poll options for Question activities. *)
488488+ (** [any_of t] returns multiple-choice poll options for Question activities.
489489+ *)
502490503491 val closed : t -> Datetime.t option
504492 (** [closed t] returns when the poll was closed, for Question activities. *)
···509497510498(** Activity reference - can be URI or full Activity. *)
511499module Activity_ref : sig
512512- type t =
513513- | Uri of Uri.t
514514- | Activity of Activity.t
500500+ type t = Uri of Uri.t | Activity of Activity.t
515501516502 val uri : Uri.t -> t
517503 val activity : Activity.t -> t
···534520 ?last:Uri.t ->
535521 ?items:'a list ->
536522 ordered:bool ->
537537- unit -> 'a t
523523+ unit ->
524524+ 'a t
538525 (** Create a new Collection. Use [~ordered:true] for OrderedCollection. *)
539526540527 val context : 'a t -> Context.t option
···553540(** {1 Collection Page} *)
554541555542(** Collection page objects.
556556- @see <https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage> *)
543543+ @see <https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage>
544544+*)
557545module Collection_page : sig
558546 type 'a t
559547···569557 ?part_of:Uri.t ->
570558 ?items:'a list ->
571559 ordered:bool ->
572572- unit -> 'a t
573573- (** Create a new CollectionPage. Use [~ordered:true] for OrderedCollectionPage. *)
560560+ unit ->
561561+ 'a t
562562+ (** Create a new CollectionPage. Use [~ordered:true] for
563563+ OrderedCollectionPage. *)
574564575565 val context : 'a t -> Context.t option
576566 val id : 'a t -> Uri.t option
···593583(** Activity collection. *)
594584module Activity_collection : sig
595585 type t = Activity.t Collection.t
586586+596587 val jsont : t Json.codec
597588end
598589599590(** Object collection. *)
600591module Object_collection : sig
601592 type t = Object.t Collection.t
593593+602594 val jsont : t Json.codec
603595end
604596605597(** Activity collection page. *)
606598module Activity_collection_page : sig
607599 type t = Activity.t Collection_page.t
600600+608601 val jsont : t Json.codec
609602end
610603611604(** Object collection page. *)
612605module Object_collection_page : sig
613606 type t = Object.t Collection_page.t
607607+614608 val jsont : t Json.codec
615609end
616610···628622 ?type_:string ->
629623 ?href:Uri.t ->
630624 ?template:string ->
631631- unit -> t
625625+ unit ->
626626+ t
632627633628 val rel : t -> string
634629 val type_ : t -> string option
635630 val href : t -> Uri.t option
636631 val template : t -> string option
637637-638632 val jsont : t Json.codec
639633 end
640634···645639 ?aliases:string list ->
646640 ?properties:(string * string) list ->
647641 ?links:Jrd_link.t list ->
648648- unit -> t
642642+ unit ->
643643+ t
649644650645 val subject : t -> string
651646 val aliases : t -> string list option
652647 val properties : t -> (string * string) list option
653648 val links : t -> Jrd_link.t list option
654654-655649 val jsont : t Json.codec
656650end
657651···669663 version:string ->
670664 ?repository:Uri.t ->
671665 ?homepage:Uri.t ->
672672- unit -> t
666666+ unit ->
667667+ t
673668674669 val name : t -> string
675670 val version : t -> string
676671 val repository : t -> Uri.t option
677672 val homepage : t -> Uri.t option
678678-679673 val jsont : t Json.codec
680674 end
681675···689683 ?users_active_month:int ->
690684 ?local_posts:int ->
691685 ?local_comments:int ->
692692- unit -> t
686686+ unit ->
687687+ t
693688694689 val users_total : t -> int option
695690 val users_active_half_year : t -> int option
696691 val users_active_month : t -> int option
697692 val local_posts : t -> int option
698693 val local_comments : t -> int option
699699-700694 val jsont : t Json.codec
701695 end
702696···709703 usage:Usage.t ->
710704 open_registrations:bool ->
711705 ?metadata:Json.t ->
712712- unit -> t
706706+ unit ->
707707+ t
713708714709 val version : t -> string
715710 val software : t -> Software.t
···717712 val usage : t -> Usage.t
718713 val open_registrations : t -> bool
719714 val metadata : t -> Json.t option
720720-721715 val jsont : t Json.codec
722716end