objective categorical abstract machine language personal data server

hermes: Return bytes for bytes output

futur.blue c14cf473 791c68e2

verified
+2 -2
hermes-cli/lib/codegen.ml
··· 423 423 (* generate output type *) 424 424 ( if output_is_bytes then begin 425 425 emitln out " (** raw bytes output with content type *)" ; 426 - emitln out " type output = string * string" ; 426 + emitln out " type output = bytes * string" ; 427 427 emit_newline out 428 428 end 429 429 else ··· 564 564 (* generate output type *) 565 565 ( if output_is_bytes then begin 566 566 emitln out " (** raw bytes output with content type *)" ; 567 - emitln out " type output = (string * string) option" ; 567 + emitln out " type output = (bytes * string) option" ; 568 568 emit_newline out 569 569 end 570 570 else
+3 -3
hermes-cli/test/test_codegen.ml
··· 110 110 [make_def "result" (Lexicon_types.Union union_spec)] 111 111 in 112 112 let code = Codegen.gen_lexicon_module doc in 113 - check bool "contains type result" true (contains code "type result =") ; 113 + check bool "contains type result" true (contains code "type result_ =") ; 114 114 check bool "contains TypeA variant" true (contains code "| TypeA of") ; 115 115 check bool "contains TypeB variant" true (contains code "| TypeB of") ; 116 116 check bool "contains Unknown (open)" true ··· 452 452 in 453 453 let code = Codegen.gen_lexicon_module doc in 454 454 check bool "contains module Main" true (contains code "module Main = struct") ; 455 - check bool "output is string * string tuple" true 456 - (contains code "type output = string * string") ; 455 + check bool "output is bytes * string tuple" true 456 + (contains code "type output = bytes * string") ; 457 457 check bool "calls Hermes.query_bytes" true 458 458 (contains code "Hermes.query_bytes") 459 459
+1 -1
hermes/README.md
··· 281 281 Endpoints with non-JSON encoding are automatically detected and handled: 282 282 283 283 - **Queries with bytes output** (e.g., `com.atproto.sync.getBlob` with `encoding: "*/*"`): 284 - - Output type is `string * string` (data, content_type) 284 + - Output type is `bytes * string` (data, content_type) 285 285 - Generated code uses `Hermes.query_bytes` 286 286 287 287 - **Procedures with bytes input**:
+12 -10
hermes/lib/client.ml
··· 36 36 -> (Yojson.Safe.t -> ('a, string) result) 37 37 -> 'a Lwt.t 38 38 39 - val query_bytes : t -> string -> Yojson.Safe.t -> (string * string) Lwt.t 39 + val query_bytes : t -> string -> Yojson.Safe.t -> (bytes * string) Lwt.t 40 40 41 41 val procedure_bytes : 42 42 t 43 43 -> string 44 44 -> Yojson.Safe.t 45 - -> string option 45 + -> bytes option 46 46 -> content_type:string 47 - -> (string * string) option Lwt.t 47 + -> (bytes * string) option Lwt.t 48 48 49 49 val procedure_blob : 50 50 t ··· 229 229 Types.raise_xrpc_error ~status payload 230 230 231 231 let query_bytes (t : t) (nsid : string) (params : Yojson.Safe.t) : 232 - (string * string) Lwt.t = 232 + (bytes * string) Lwt.t = 233 233 (* call interceptor if present for token refresh *) 234 234 let* () = 235 235 match t.on_request with Some f -> f t | None -> Lwt.return_unit ··· 249 249 in 250 250 let status = Cohttp.Response.status resp |> Cohttp.Code.code_of_status in 251 251 let* body_str = Cohttp_lwt.Body.to_string body in 252 + let body = Bytes.of_string body_str in 252 253 if status >= 200 && status < 300 then 253 254 let content_type = 254 255 Cohttp.Response.headers resp ··· 256 257 Cohttp.Header.get h "content-type" 257 258 |> Option.value ~default:"application/octet-stream" 258 259 in 259 - Lwt.return (body_str, content_type) 260 + Lwt.return (body, content_type) 260 261 else 261 262 let payload = 262 263 try ··· 272 273 273 274 (* execute procedure with raw bytes input, returns raw bytes or none if no output *) 274 275 let procedure_bytes (t : t) (nsid : string) (params : Yojson.Safe.t) 275 - (input : string option) ~(content_type : string) : 276 - (string * string) option Lwt.t = 276 + (input : bytes option) ~(content_type : string) : 277 + (bytes * string) option Lwt.t = 277 278 (* call interceptor if present for token refresh *) 278 279 let* () = 279 280 match t.on_request with Some f -> f t | None -> Lwt.return_unit ··· 286 287 let body = 287 288 match input with 288 289 | Some data -> 289 - Cohttp_lwt.Body.of_string data 290 + Cohttp_lwt.Body.of_string (Bytes.to_string data) 290 291 | None -> 291 292 Cohttp_lwt.Body.empty 292 293 in ··· 303 304 in 304 305 let status = Cohttp.Response.status resp |> Cohttp.Code.code_of_status in 305 306 let* body_str = Cohttp_lwt.Body.to_string resp_body in 307 + let body = Bytes.of_string body_str in 306 308 if status >= 200 && status < 300 then 307 - if String.length body_str = 0 then Lwt.return None 309 + if Bytes.length body = 0 then Lwt.return None 308 310 else 309 311 let resp_content_type = 310 312 Cohttp.Response.headers resp ··· 312 314 Cohttp.Header.get h "content-type" 313 315 |> Option.value ~default:"application/octet-stream" 314 316 in 315 - Lwt.return (Some (body_str, resp_content_type)) 317 + Lwt.return (Some (body, resp_content_type)) 316 318 else 317 319 let payload = 318 320 try
+6 -6
hermes/lib/hermes.mli
··· 77 77 -> (Yojson.Safe.t -> ('a, string) result) 78 78 -> 'a Lwt.t 79 79 80 - val query_bytes : client -> string -> Yojson.Safe.t -> (string * string) Lwt.t 80 + val query_bytes : client -> string -> Yojson.Safe.t -> (bytes * string) Lwt.t 81 81 82 82 val procedure_bytes : 83 83 client 84 84 -> string 85 85 -> Yojson.Safe.t 86 - -> string option 86 + -> bytes option 87 87 -> content_type:string 88 - -> (string * string) option Lwt.t 88 + -> (bytes * string) option Lwt.t 89 89 90 90 val session_to_yojson : session -> Yojson.Safe.t 91 91 ··· 158 158 -> (Yojson.Safe.t -> ('a, string) result) 159 159 -> 'a Lwt.t 160 160 161 - val query_bytes : t -> string -> Yojson.Safe.t -> (string * string) Lwt.t 161 + val query_bytes : t -> string -> Yojson.Safe.t -> (bytes * string) Lwt.t 162 162 163 163 val procedure_bytes : 164 164 t 165 165 -> string 166 166 -> Yojson.Safe.t 167 - -> string option 167 + -> bytes option 168 168 -> content_type:string 169 - -> (string * string) option Lwt.t 169 + -> (bytes * string) option Lwt.t 170 170 171 171 val procedure_blob : 172 172 t
+9 -3
hermes/test/test_client.ml
··· 7 7 (* helpers *) 8 8 let test_string = testable Fmt.string String.equal 9 9 10 + let test_bytes = 11 + testable 12 + (Fmt.of_to_string (fun b -> String.sub (Bytes.to_string b) 0 10)) 13 + Bytes.equal 14 + 10 15 (** query tests *) 11 16 12 17 let test_query_success () = ··· 105 110 C.query_bytes client "com.atproto.sync.getBlob" 106 111 (`Assoc [("did", `String "did:plc:123"); ("cid", `String "bafyabc")]) ) 107 112 in 108 - check test_string "data" "fake-image-data" data ; 113 + check test_bytes "data" (Bytes.of_string "fake-image-data") data ; 109 114 check test_string "content_type" "image/jpeg" content_type ; 110 115 let req = List.hd requests in 111 116 Test_utils.assert_request_has_header "accept" "*/*" req ; ··· 163 168 let* result, requests = 164 169 Test_utils.with_mock_responses [response] (fun (module C) client -> 165 170 C.procedure_bytes client "com.atproto.repo.importRepo" (`Assoc []) 166 - (Some "fake-car-data") ~content_type:"application/vnd.ipld.car" ) 171 + (Some (Bytes.of_string "fake-car-data")) 172 + ~content_type:"application/vnd.ipld.car" ) 167 173 in 168 - check (option (pair test_string test_string)) "result" None result ; 174 + check (option (pair test_bytes test_string)) "result" None result ; 169 175 let req = List.hd requests in 170 176 Test_utils.assert_request_has_header "content-type" "application/vnd.ipld.car" 171 177 req ;
+5 -5
hermes_ppx/test/test_ppx.ml
··· 19 19 check (list string) "single segment" ["Test"] result 20 20 21 21 let test_build_call_expr () = 22 - let result = Hermes_ppx.build_call_expr ~loc "app.bsky.graph.getProfile" in 23 - let expected_str = "App.Bsky.Graph.GetProfile.call" in 22 + let result = Hermes_ppx.build_call_expr ~loc "app.bsky.actor.getProfile" in 23 + let expected_str = "App.Bsky.Actor.GetProfile.Main.call" in 24 24 check string "call expr" expected_str 25 25 (Ppxlib.Pprintast.string_of_expression result) 26 26 ··· 38 38 39 39 let test_expand_get_nsid () = 40 40 let actual = expand_xrpc {|[%xrpc get "app.bsky.graph.getRelationships"]|} in 41 - let expected_str = "App.Bsky.Graph.GetRelationships.call" in 41 + let expected_str = "App.Bsky.Graph.GetRelationships.Main.call" in 42 42 check string "get expansion" expected_str 43 43 (Ppxlib.Pprintast.string_of_expression actual) 44 44 ··· 46 46 let actual = 47 47 expand_xrpc {|[%xrpc post "com.atproto.server.createSession"]|} 48 48 in 49 - let expected_str = "Com.Atproto.Server.CreateSession.call" in 49 + let expected_str = "Com.Atproto.Server.CreateSession.Main.call" in 50 50 check string "post expansion" expected_str 51 51 (Ppxlib.Pprintast.string_of_expression actual) 52 52 53 53 let test_expand_nsid_only () = 54 54 (* [%xrpc "nsid"] defaults to get *) 55 55 let actual = expand_xrpc {|[%xrpc "app.bsky.actor.getProfile"]|} in 56 - let expected_str = "App.Bsky.Actor.GetProfile.call" in 56 + let expected_str = "App.Bsky.Actor.GetProfile.Main.call" in 57 57 check string "nsid only expansion" expected_str 58 58 (Ppxlib.Pprintast.string_of_expression actual) 59 59
+1 -1
pegasus/lexicons/com_atproto_sync_getBlob.ml
··· 12 12 [@@deriving yojson {strict= false}] 13 13 14 14 (** raw bytes output with content type *) 15 - type output = string * string 15 + type output = bytes * string 16 16 17 17 let call 18 18 ~did
+1 -1
pegasus/lexicons/com_atproto_sync_getBlocks.ml
··· 12 12 [@@deriving yojson {strict= false}] 13 13 14 14 (** raw bytes output with content type *) 15 - type output = string * string 15 + type output = bytes * string 16 16 17 17 let call 18 18 ~did
+1 -1
pegasus/lexicons/com_atproto_sync_getCheckout.ml
··· 11 11 [@@deriving yojson {strict= false}] 12 12 13 13 (** raw bytes output with content type *) 14 - type output = string * string 14 + type output = bytes * string 15 15 16 16 let call 17 17 ~did
+1 -1
pegasus/lexicons/com_atproto_sync_getRecord.ml
··· 13 13 [@@deriving yojson {strict= false}] 14 14 15 15 (** raw bytes output with content type *) 16 - type output = string * string 16 + type output = bytes * string 17 17 18 18 let call 19 19 ~did
+1 -1
pegasus/lexicons/com_atproto_sync_getRepo.ml
··· 12 12 [@@deriving yojson {strict= false}] 13 13 14 14 (** raw bytes output with content type *) 15 - type output = string * string 15 + type output = bytes * string 16 16 17 17 let call 18 18 ~did
+8 -18
pegasus/lib/api/account_/migrate/migrate.ml
··· 417 417 match%lwt Remote.fetch_repo old_client ~did with 418 418 | Error err -> 419 419 render_err ~did ~handle ~old_pds ("Failed to fetch repository: " ^ err) 420 - | Ok car_data -> ( 421 - match%lwt 422 - Ops.import_repo ~did ~car_data:(Bytes.of_string (fst car_data)) 423 - with 420 + | Ok (car_data, _) -> ( 421 + match%lwt Ops.import_repo ~did ~car_data with 424 422 | Error err -> 425 423 render_err ~did ~handle ~old_pds err 426 424 | Ok () -> ··· 432 430 match%lwt Remote.fetch_repo old_client ~did with 433 431 | Error e -> 434 432 render_err ("Failed to fetch repository: " ^ e) 435 - | Ok car_data -> ( 436 - match%lwt 437 - Ops.import_repo ~did ~car_data:(Bytes.of_string (fst car_data)) 438 - with 433 + | Ok (car_data, _) -> ( 434 + match%lwt Ops.import_repo ~did ~car_data with 439 435 | Error e -> 440 436 render_err e 441 437 | Ok () -> ( ··· 784 780 match%lwt Remote.fetch_repo client ~did with 785 781 | Error e -> 786 782 render_err ("Failed to fetch repository: " ^ e) 787 - | Ok car_data -> ( 788 - match%lwt 789 - Ops.import_repo ~did 790 - ~car_data:(Bytes.of_string @@ fst car_data) 791 - with 783 + | Ok (car_data, _) -> ( 784 + match%lwt Ops.import_repo ~did ~car_data with 792 785 | Error e -> 793 786 render_err e 794 787 | Ok () -> ··· 885 878 | Error e -> 886 879 render_err ~did ~handle ~old_pds 887 880 ("Failed to fetch repository: " ^ e) 888 - | Ok car_data -> ( 889 - match%lwt 890 - Ops.import_repo ~did 891 - ~car_data:(Bytes.of_string @@ fst car_data) 892 - with 881 + | Ok (car_data, _) -> ( 882 + match%lwt Ops.import_repo ~did ~car_data with 893 883 | Error e -> 894 884 render_err ~did ~handle ~old_pds e 895 885 | Ok () -> (
+1 -3
pegasus/lib/api/account_/migrate/ops.ml
··· 125 125 | Error _ -> 126 126 Lwt.return_error cid_str 127 127 | Ok cid -> 128 - let%lwt _ = 129 - User_store.put_blob user_db cid mimetype (Bytes.of_string data) 130 - in 128 + let%lwt _ = User_store.put_blob user_db cid mimetype data in 131 129 Lwt.return_ok cid_str ) ) 132 130 cids 133 131 in