Repository navigation
v4.0.0
connect-library 4.0.0, attachment-receiver 4.0.0, connect-e2ee 4.0.0 (new)
Major version. Adds optional end-to-end encryption of Connect cases and notes, to the tsanet-e2ee-1 profile in the workgroup specification "Connect E2E Encryption" (tsanetgit/Connect_SDK#140). The platform holds no keys: each member encrypts and signs at its own connector. A connector that doesn't use E2EE needs no change to its calls. Runtime unchanged: Spring Boot 4.1, Jackson 3, JDK 21.
This release also carries everything in 3.0.0 (published 2026-10-21), repeated under "Included from 3.0.0" so a member coming from 2.0.0 has one list. Coming from 2.0.0, apply the 3.0.0 changes first.
The full upgrade guide is the 3.0.0 and 4.0.0 entries in skills/connect-sdk-deploy/references/consume-artifact.md.
New in 4.0.0
connect-e2ee, a new optional artifact (#143). It encrypts and signs a case or note for a create, and verifies and decrypts one on a read.- Sending:
E2eeProfile.encryptCaseandencryptNotecheck the plaintext (required form fields and the spec's lengths), encrypt each protected field for the partner and the sender, and sign a manifest. The result goes straight into the create overloads below. - Receiving:
verifyCaseandverifyNoterun the profile's six checks in order. The result is the decrypted content, or a refusal naming the step and the field that never carries a value. There is no plaintext fallback. - Keys: private keys stay behind
KeyOperations, so they can live in a key service (SoftwareKeyOperationsis for tests). Partner public keys come from pinned JWKS URLs (PinnedJwksPartnerKeys). - Replay: a
ReplayGuardchecks first receipt (an in-memory one is included). - Dependency: the module brings
com.nimbusds:nimbus-jose-jwt10.10. A connector that doesn't add the module gets no JOSE library. - Setup and the full API are in
connect-e2ee/README.md.
- Sending:
connect-librarycarries the E2EE fields (#141, #142).createRequest(both forms) andcreateNotegain an overload takingE2eeFields(manifest, encrypted), sent exactly as given. Withencryptedtrue, values are sent unstripped and the note length limits don't apply.CaseNoteDtogainsmanifestandencrypted.CollaborationRequestStatusDtogainsmanifest,encrypted,submitterCaseNumber,descriptionandcustomFields(CaseCustomFieldDto(id, fieldName, value)).- The SQLite cache stores all of them, adding the columns to an existing cache on first open.
Breaking changes in 4.0.0
Existing calls compile, and a consumer that bumps without recompiling still links. Two kinds of code break at source, which is why this is a major:
- Implementers and decorators of
CollaborationRequestsFacadeorCaseNotesFacademust add the new abstract overloads, and move their logic to them. The old overloads now forward to the new ones, so an override of the old overload alone no longer sees an E2EE create. Point interceptors and test stubs at the new overloads too.E2eeFieldsis inconnect-library, so this needs noconnect-e2ee. - Record patterns over
CaseNoteDtoorCollaborationRequestStatusDtogain components, so a 3.0.0 pattern stops compiling. The earlier constructors are deprecated but still work, which a-Werrorbuild will flag.
Also check in 4.0.0
- Records cached by 3.0.0 read the new components as null ("not known") until fetched again. On stored reads, null-check
customFieldsand testBoolean.TRUE.equals(encrypted())rather than unboxingencrypted(), which throws on an old row. For the same reason an old record doesn't equal a fresh read of the same case or note. - Logs and JSON:
toStringand JSON serialization include the new components, so logging or forwarding aCollaborationRequestStatusDtonow carries the case's description and custom-field answers, not only its summary. - Case text on disk: the cache now holds each case's description and custom-field answers as well as its summary. For an encrypted case it holds the ciphertext the platform returned;
connect-e2eenever writes decrypted text to it.CacheRetention.sweepevicts closed and rejected cases; it never sweeps an open one.
Known limits in 4.0.0
- Form rules:
connect-e2eechecksrequiredand lengths, but not a form field'soptionsorvalidationRules, whose format the API doesn't document (tsanetgit/Connect-API-Code#221). - Two encryption keys: a partner publishing two encryption keys is refused until the workgroup sets a rule. Publish only your current encryption key.
- Sanitizer workaround: while the API's sanitizer rewrites encrypted values (
tsanetgit/Connect-API-Code#214), the module restores them before checking, as the Power App does.
Included from 3.0.0
The V2 attachment client is rebuilt on the grant model in the Connect OpenAPI spec, and its public types change incompatibly. Senders can restrict which companies receive their V2 attachments, and receivers can configure their own storage. Case notes take their types from the server. /v1/ failures now arrive as problem details, and Connect API calls run on the JDK's HTTP client.
Breaking changes in 3.0.0
-
The V2 attachment client is rebuilt from the spec (#96, #100).
attachmentsV2()has one method per Connect API call:createGrant,getGrant,listGrants,singleUploadLink,s3PartLinks,azureBlockLinks, the threecomplete*calls andabandon. It also keepscompletefor the grant's mode,uploadand a four-argumentsendthat returns the completedAttachmentGrant.- Removed:
grant, the olduploadandcompletesignatures, the six-argumentsend, andAttachmentGrantRequest,AttachmentCompleteRequestandAttachmentCompleteResult. AttachmentGrantis now the server's grant: alongid,Status,UploadModeandUploadPlan. It takes no content type, SHA-256 or description, and has noDELIVEREDor note-id outcome.AttachmentV2Exception:problemType()andisProblemare replaced bycode()andis(code), with codes chosen by HTTP status. Several 2.0.0 codes are removed; the upgrade guide maps each one.sendno longer re-grants when a grant expires before complete.
- Removed:
-
/v1/failures are problem details (#127, #129). The library now sendsAccept: application/json, application/problem+json. A failed/v1/call now carries the documented4xxstatus where 2.0.0 often saw a500, withtype()andtitle()set, and the message readsHTTP <status> <title> (<type suffix>): <detail>. Code that branches onkind() == LEGACY, onstatus()or on the message text sees different values: sweep for it. A wrong password is aPROBLEMtoo. -
Connect API calls use
java.net.http.HttpClient(#128, #131 to #134), one client per session. The JVM's proxy selector and SSL context still apply.- No longer honored: a default
Authenticatorfor an authenticating proxy, andHttpsURLConnection's default socket factory and hostname verifier. - Redirects: a redirected
GETis no longer followed. Any3xxisOTHER, and the message never names theLocation. - Interrupts: an interrupted call stops with
OTHER, status 0, and leaves the thread interrupted.
- No longer honored: a default
-
Interface and record changes.
TsaNetApiSessiongainsattachmentStorage().CaseNotesFacadegainslistNoteTypes()and a five-argumentcreateNote.ApplicationUserAccountandTsaNetApiConfigurationgain anallowedReceiverCompanyIdscomponent.CaseNoteDtogrows from 14 to 18 components.
Callers are unaffected. Implementers and decorators must add the new methods. A record pattern over a changed record stops compiling. The 2.0.0 constructors still compile, and the
CaseNoteDtoone is deprecated. -
A V2 upload link missing
expiresAtorsizeBytesis refused (#138). An upload-link answer withoutexpiresAt(any link), or withoutsizeBytes(an S3 part or Azure block), fails withAttachmentV2ExceptionCLIENT_PRECONDITION"the answer has no ...". It used to silently turn off link refresh or the part-size check. The spec requires both fields, and the platform sends them.
New in 3.0.0
- Receiver allowlist, part 1 of #92 (#104). Set it with
ApplicationUserAccount.withAllowedReceiverCompanyIds, or withallowed-receiver-company-idsin the console's account config.- With a list set:
createGrant(and sosend) refuses a case whose receiving company isn't on it withattachment/receiver-not-allowed, before any grant is requested. The platform's own allowlist refusal (403) is reported as the same code. - Empty or null: unrestricted.
- With a list set:
- Receiver storage (#106, #107).
session.attachmentStorage()gets, registers and tests the company's S3 or Azure Blob storage. The demo-ui has a Settings page for it, read-only unlessTSANET_DEMO_RECEIVER_STORAGE_EDITABLEis set. - Note types from the server (#99, #103, reworked in #124 to #126).
- Listing types:
listNoteTypes()returns the codes a caller may send, fromGET /v1/note-types. - Creating:
createNote(..., type)sends the code as given, and a code the server doesn't offer is a400invalid-note-type. - No default: a null type creates a note with no type, and nothing becomes
partner. - Reading notes: they carry
type,typeDisplayName,companyIdanddirection. - The SQLite cache adds the four columns at startup.
- Listing types:
- Upload loop on the spec's links.
- Links: requested just before use, in batches of up to 1,000, and refreshed when they expire within 60 seconds.
- Retries: bounded per part, honoring
Retry-After. - Wire: link headers are sent unchanged, S3 ETags are kept for complete, and links never appear in logs or messages.
Unchanged
- V1 attachments and every other existing call, apart from the additions above.
- Runtime line: Spring Boot 4.1, Jackson 3, JDK 21.
attachment-receiver: its source is unchanged since 2.0.0. It is published at 4.0.0 because the modules release together.
Consuming the artifacts
Get com.tsanet:connect-library:4.0.0, com.tsanet:attachment-receiver:4.0.0 and, for E2EE, com.tsanet:connect-e2ee:4.0.0 from https://maven.pkg.github.com/tsanetgit/Connect_SDK. A read:packages token is required even for public packages.
Building from source needs a Connect-API-Code spec branch that has the Attachment Grants and Attachment Storage Config operations and the E2EE fields. beta has them.
The V2 attachment endpoints are x-stability-level: alpha in the spec.
Known consumers
tsanetgit/Connect_Gatewaypinsconnect-library3.0.0 (gateway-engine/pom.xml). Taking E2EE istsanetgit/Connect_Gateway#51: bump to 4.0.0, addconnect-e2ee, and wire it into create and fetch. The 4.0.0 facade change applies to any decorator it has.tsanetgit/Fin-Intercom_Appconsumesgateway-engine, so it follows the gateway.
Verification
-
CI at the release commit:
verifyonmain3adf1a3(the merge of #145), built against Connect-API-Codebeta46fc91f. Every module passed with zero failures:Module Tests connect-library 317 connect-e2ee 57 scripted demo 9 console 44 attachment-receiver 182 (40 environment-gated live tests skipped) demo-ui 44 -
Cross-implementation:
connect-e2eedecrypts and verifies the specification's worked example (Addendum D), which was generated independently with other JOSE libraries, for both members. The tests include every refusal step and 35 red probes, each removing one check and showing a test fail. -
Reviews: #141, #142 and #143 each had a design-critic run, the pre-PR gate, auto-QA and a separate-session QA review, with every finding dispositioned on its PR. The upgrade guide (#144) had two separate-session QA rounds. 3.0.0 had a whole-branch design review of its promotion (#136).
-
Live on BETA for 3.0.0 (2026-10-21): the demo-ui image built from the 3.0.0 release commit
23b7489sent two V2 attachments as a test member, to a test receiver whose storage is an S3 bucket: a 1 MiB file insinglemode and a 12 MiB file ins3Multipartmode (three 5 MiB parts), both grants completed. -
Not yet done for 4.0.0: a live round trip with the Power App on DEV or Beta (
tsanetgit/Connect_SDK#140).