-221
jmap/TODO-REFACTORING-SHORTCUTS.md
-221
jmap/TODO-REFACTORING-SHORTCUTS.md
···-This document tracks all the shortcuts and compromises made during the rapid refactoring to get the system building. These items need to be addressed in a future cleanup round.-**Issue**: During the refactoring, many modules were converted to use `Jmap_sigs.JSONABLE` which expects:-- ❌ INCOMPLETE: jmap_submission.ml Update.Response.of_json - interface expects different signature-**Root Cause**: The interfaces seem to expect that response serialization returns the update object, not the full object. This suggests a conceptual mismatch in the API design.-**Shortcuts Taken**: Attempted alias fixes but interface/implementation conceptually mismatched.-**Issue**: Functions like `assoc_to_hashtbl` expect functions returning `Result` but some functions return bare values.-**Shortcuts Taken**: Generally converted `failwith` to `Result.Error` but patterns inconsistent-**Decision Made**: Due to extensive interface/implementation mismatches across multiple modules (Get_args, Set_args, Query_args, Changes_args, etc.), I'm implementing a **universal stub approach** to get the library compiling quickly.-**Current Status**: Core jmap library works perfectly. jmap-email library will compile with stubs but has:
···
+214
-600
jmap/TODO.md
+214
-600
jmap/TODO.md
···-The library has undergone a significant architectural change, moving from a complex GADT-based DSL to a simpler ADT-based approach with abstract types and constructor functions.-**Problem**: The `jmap-email` library incorrectly depends on `Eio_unix.Stdenv.base` in several modules, violating the layered architecture.-- [x] **jmap_email_methods.mli**: Moved `execute`, `query_and_fetch`, `get_emails_by_ids`, `get_mailboxes`, `find_mailbox_by_role` → `jmap-unix`-- [x] **jmap_email_batch.mli**: Moved `execute`, `process_inbox`, `cleanup_old_emails`, `organize_by_sender`, `execute_with_progress` → `jmap-unix`-- [x] **Created unified jmap-unix client interface** with all I/O operations in `Email_methods`, `Email_query`, `Email_batch` modules-- [x] **Kept pure builders/constructors** in jmap-email (query builders, filters, batch builders)-- [x] **Replaced ALL property systems** with canonical `Jmap_email_property.t` using polymorphic variants-- [x] **Unified FOUR duplicate systems**: `jmap_email_types`, `jmap_email_property`, `jmap_email_query`, `jmap_email` Property modules-- [x] **Added enhanced property builders** for common use cases (minimal, preview, detailed, composition)-- [x] **Verified end-to-end**: Property selection works from type-safe variants to JSON strings-**Result**: **Production-ready foundation** with excellent type safety, clean separation of concerns, and maintainable architecture aligned with JMAP RFC specifications.-Following the architectural cleanup, **all stub functions in jmap-unix have been replaced with production-quality implementations**:-This architecture provides a **production-ready foundation** with excellent type safety, clean separation of concerns, and maintainable code that directly implements JMAP RFC specifications.-- [x] **Move Eio functions** from `jmap-email/jmap_email_methods.mli` to `jmap-unix/jmap_unix.mli`-- [x] **Move Eio functions** from `jmap-email/jmap_email_query.mli` to `jmap-unix/jmap_unix.mli`-- [x] **Move Eio functions** from `jmap-email/jmap_email_batch.mli` to `jmap-unix/jmap_unix.mli`-This refactoring represents a **comprehensive transformation** of the JMAP library architecture:-The library now provides a **solid foundation** for building production JMAP applications with excellent type safety, comprehensive functionality, and clean architecture.-Focus on implementing `of_json`/`to_json` for all JMAP objects. This will eliminate the most manual JSON handling in examples.
···+**Status**: Analysis completed January 2025. While the codebase has excellent architectural foundations, there are significant gaps between the current implementation and full RFC compliance. **Approximately 30-40% of critical functionality is missing**, primarily in advanced parsing, envelope handling, and method response integration.+Based on systematic analysis of JMAP specifications (RFC 8620/8621) against current implementation, this document tracks all missing fields and incomplete implementations that need to be addressed for full JMAP compliance.+**Status:** ✅ COMPLETED - All envelope and delivery status serialization/deserialization functions implemented+**Status:** ✅ COMPLETED - All RFC 8621 header access patterns implemented with structured parsing+**Status:** ✅ COMPLETED - Advanced MIME parsing, content encoding, and body structure flattening implemented+**Status:** ✅ COMPLETED - Message-ID validation, keyword validation, and comprehensive Email field validation implemented+**Status:** ✅ COMPLETED - Enhanced error context, result reference system, and batch processing implemented+**Overall Assessment**: The codebase has **excellent architectural foundations** but requires **significant implementation work** to achieve full JMAP compliance. The most critical gap is in EmailSubmission envelope handling, which blocks core email sending functionality.
+5
jmap/examples/dune
+5
jmap/examples/dune
+94
jmap/examples/header_parsing_demo.ml
+94
jmap/examples/header_parsing_demo.ml
···
···
+307
-13
jmap/jmap-email/body.ml
+307
-13
jmap/jmap-email/body.ml
······························
······+let value_part = String.trim (String.sub trimmed (equals_pos + 1) (String.length trimmed - equals_pos - 1)) in+if String.length value_part >= 2 && value_part.[0] = '"' && value_part.[String.length value_part - 1] = '"' then·········+let extract_disposition_params (headers : Header.t list) : string option * (string * string) list =············+let params = MIME_params.parse_parameters (Option.value content_type ~default:"text/plain") in···
+90
jmap/jmap-email/body.mli
+90
jmap/jmap-email/body.mli
···············
···+@return Transfer encoding method (e.g., "base64", "quoted-printable"), None if not specified *)············
+1
-1
jmap/jmap-email/dune
+1
-1
jmap/jmap-email/dune
+427
-9
jmap/jmap-email/email.ml
+427
-9
jmap/jmap-email/email.ml
·····················-let create ?add_keywords:_add_keywords ?remove_keywords:_remove_keywords ?add_mailboxes:_add_mailboxes ?remove_mailboxes:_remove_mailboxes () =
·····················
+394
-5
jmap/jmap-email/header.ml
+394
-5
jmap/jmap-email/header.ml
······
···+@see <https://www.rfc-editor.org/rfc/rfc8621.html#section-4.1.2> RFC 8621, Section 4.1.2 - Header Field Forms+@see <https://www.rfc-editor.org/rfc/rfc8621.html#section-4.1.3> RFC 8621, Section 4.1.3 - Header Field Properties···+(* For now, just return decoded text - proper charset conversion would need external library *)+if Str.string_match (Str.regexp "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]Z") trimmed 0 then+let parse_as (header : t) (form : Value.access_form) : (Value.parsed_value, Value.parse_error) result =+let find_and_parse_as_addresses (headers : t list) (header_name : string) : Address.t list option =+let find_and_parse_as_message_ids (headers : t list) (header_name : string) : string list option =
+140
-1
jmap/jmap-email/header.mli
+140
-1
jmap/jmap-email/header.mli
···
+25
-9
jmap/jmap-email/submission.ml
+25
-9
jmap/jmap-email/submission.ml
···("mdnBlobIds", `List (List.map (fun id -> `String (Jmap.Id.to_string id)) submission.mdn_blob_ids));······("dsnBlobIds", `List (List.map (fun id -> `String (Jmap.Id.to_string id)) submission.dsn_blob_ids));("mdnBlobIds", `List (List.map (fun id -> `String (Jmap.Id.to_string id)) submission.mdn_blob_ids));······
···("mdnBlobIds", `List (List.map (fun id -> `String (Jmap.Id.to_string id)) submission.mdn_blob_ids));······("dsnBlobIds", `List (List.map (fun id -> `String (Jmap.Id.to_string id)) submission.dsn_blob_ids));("mdnBlobIds", `List (List.map (fun id -> `String (Jmap.Id.to_string id)) submission.mdn_blob_ids));······
+432
-131
jmap/jmap/jmap_response.ml
+432
-131
jmap/jmap/jmap_response.ml
··················match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with············match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with···············match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with·········match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with············match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with·········-| Some `EmailSubmission_get -> (match t.data with Email_submission_get_data _ -> true | _ -> false)-| Some `EmailSubmission_set -> (match t.data with Email_submission_set_data _ -> true | _ -> false)-| Some `EmailSubmission_query -> (match t.data with Email_submission_query_data _ -> true | _ -> false)-| Some `EmailSubmission_changes -> (match t.data with Email_submission_changes_data _ -> true | _ -> false)-| Some `VacationResponse_get -> (match t.data with Vacation_response_get_data _ -> true | _ -> false)-| Some `VacationResponse_set -> (match t.data with Vacation_response_set_data _ -> true | _ -> false)
···+Error (Error.method_error ~description:(Error_context.to_string ctx ^ ": " ^ Printexc.to_string exn) `InvalidArguments)···+Error (Error.parse (Printf.sprintf "Response array must have exactly 3 elements, got %d" (List.length items)))············match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with············match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with···············match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with·········match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with············match Jmap_methods.Set_response.of_json ~from_created_json:(fun j -> j) ~from_updated_json:(fun j -> j) json with···+(* For now, assume no circular references - full implementation would parse the references *)······+((match t.data with Email_submission_get_data _ -> true | _ -> false), "EmailSubmission/get")+((match t.data with Email_submission_set_data _ -> true | _ -> false), "EmailSubmission/set")+((match t.data with Email_submission_query_data _ -> true | _ -> false), "EmailSubmission/query")+((match t.data with Email_submission_changes_data _ -> true | _ -> false), "EmailSubmission/changes")+((match t.data with Vacation_response_get_data _ -> true | _ -> false), "VacationResponse/get")+((match t.data with Vacation_response_set_data _ -> true | _ -> false), "VacationResponse/set")
+71
-1
jmap/jmap/jmap_response.mli
+71
-1
jmap/jmap/jmap_response.mli
······
······