diff --git a/.fernignore b/.fernignore index e6be721..c938409 100644 --- a/.fernignore +++ b/.fernignore @@ -1,2 +1,3 @@ # Specify files that shouldn't be modified by Fern changelog.md +migration-from-vital/ diff --git a/migration-from-vital/CHANGELOG.md b/migration-from-vital/CHANGELOG.md new file mode 100644 index 0000000..69d93d1 --- /dev/null +++ b/migration-from-vital/CHANGELOG.md @@ -0,0 +1,103 @@ +# Changelog + +_Major release. Baseline: `tryVital/vital-java@1.2.588`._ + +## Breaking changes + +- **Maven coordinate renamed** — [migration steps](MIGRATION.md#install) + The Java SDK is published under a new Maven coordinate: + + - `io.tryvital:vital-java` → `com.junction:junction-java` + + The old artifact will not receive further releases — replace your dependency declaration and re-resolve. This is a coordinate replacement, not a version bump: it ships alongside the package-prefix and class renames, so an in-place version update will not compile. +- **Environment URLs moved to junction.com hosts** — [migration steps](MIGRATION.md#rename-environment-enum) + Every base URL exposed by the SDK has been replaced as part of the rebrand: + + - `https://api.tryvital.io` → `https://api.us.junction.com` + - `https://api.eu.tryvital.io` → `https://api.eu.junction.com` + - `https://api.sandbox.tryvital.io` → `https://api.sandbox.us.junction.com` + - `https://api.sandbox.eu.tryvital.io` → `https://api.sandbox.eu.junction.com` + + Callers that pass `Environment.PRODUCTION` (or the other constants) pick up the new URL automatically because the constant value changed; callers that pass a literal URL string — or that compare against the old URL — must update those references. The `Environment` class name itself is unchanged. +- **Exception and HTTP-response types renamed** — [migration steps](MIGRATION.md#rename-exception-types) + Two SDK-level types have been renamed: + + - `VitalException` → `JunctionException` (the top-level exception thrown by every SDK call) + - `VitalHttpResponse` → `JunctionHttpResponse` (the wrapper returned by raw-response variants) + + Update `catch` clauses and any helper signatures that mention these types. +- **Java package path moved to `com.junction.api`** — [migration steps](MIGRATION.md#rename-package-prefix) + Every generated type now lives under the `com.junction.api` package tree instead of `com.vital.api`. Every `import com.vital...` statement in your codebase needs to become `import com.junction...` — this affects models, request/response types, errors, and the client itself. +- **Top-level client class renamed** — [migration steps](MIGRATION.md#rename-client-class) + The entry-point client classes have been renamed across the SDK: + + - `Vital` → `Junction` + - `VitalBuilder` → `JunctionBuilder` + - `AsyncVital` → `AsyncJunction` + - `AsyncVitalBuilder` → `AsyncJunctionBuilder` + + Update construction sites and any helper methods or fields that hold a typed client reference. +- **Path parameters are now positional arguments** — [migration steps](MIGRATION.md#inline-path-parameters) + Every endpoint that takes a path parameter accepts it as a positional argument on the method instead of nested inside a request-object builder. For example, `client.user().get(userId)` replaces the old pattern that built a `UserGetRequest` to hold the `userId`. Body and query parameters are unchanged: pass them as the second argument when present. +- **Per-endpoint request types renamed verb-first** — [migration steps](MIGRATION.md#request-type-rename) + Auto-generated request types now read fluently from the verb. For example: + + - `LabTestsGetMarkersRequest` → `GetMarkersLabTestsRequest` + - `LinkListBulkOpsRequest` → `ListBulkOpsLinkRequest` + + The same rule applies to every per-endpoint request class. If you import these types directly (for type annotations on helper methods, custom wiring, or builder reuse), update each import and reference. Most callers that just inline-build the request at the call site are unaffected. +- **Nullable model fields now surface as `Optional`** — [migration steps](MIGRATION.md#respect-nullable-schemas) + Model getters for fields that the API documents as nullable now return `Optional` (and the matching builder setters accept `null` or an empty `Optional`). Code that previously dereferenced these getters directly will not compile until you unwrap with `.orElse(...)`, `.isPresent()`, or `.get()`. The change is an accuracy fix — the API was always free to return `null` for these fields — so unwrap with a default that matches your previous expectation. + +## New & improved + +- **New top-level resources** + The SDK now exposes the `compendium`, `labaccount`, `ordertransaction` resource clients on the root client. See the API reference for the full endpoint list. +- **Pluggable logging and SSE parsing in core** + The core package now exposes a pluggable `Logger` interface (with a default `ConsoleLogger`), a `LogConfig` you can wire via the client builder, and a built-in `LoggingInterceptor` for request/response logging. Server-sent-events responses can be parsed with the new `SseEventParser` / `SseEvent` helpers. RFC-2822 timestamps deserialise correctly through the new `Rfc2822DateTimeDeserializer`. +- **List physicians on a team** + `TeamClient` now exposes `getPhysicians(GetPhysiciansTeamRequest)` for listing physicians associated with a team — see the API reference for filter details. +- **Raw response shapes formalized — `*V2InDB` types are now `*Raw`** + Endpoints whose responses were previously typed as `*V2InDB` now use `*Raw` types. The values are unchanged; only the type names differ: + + - `ActivityV2InDB` → `RawActivity` + - `BodyV2InDB` → `RawBody` + - `DeviceV2InDB` → `RawDevices` + - `SleepV2InDB` → `RawSleep` + - `WorkoutV2InDB` → `RawWorkout` + + If you imported one of the old names directly, switch to the new `Raw*` type. +- **Enums tolerate unknown values via a sentinel** — [migration steps](MIGRATION.md#forward-compatible-enums) + Every generated enum is now forward-compatible. Deserialising a wire value the SDK doesn't recognise no longer throws — it produces an enum instance whose internal value is the sentinel `_UNKNOWN`. This means future server-side enum additions stop being a hard break for older client versions. For example, an unknown `Providers` value now yields a `Providers` instance whose `getEnumValue()` returns `Providers.Value._UNKNOWN`, while `toString()` preserves the raw wire string. + + If your code uses a `switch` statement on an enum's `getEnumValue()`, add a `default` (or explicit `_UNKNOWN`) arm so unrecognised values are handled. Equality checks now compare against the sentinel rather than throwing. + +## Removed + +- **Legacy link methods removed** — [migration steps](MIGRATION.md#link-removed-legacy-endpoints) + These methods have been deprecated for over two years and were never part of the documented Junction Link integration path; they should not have been in the SDK in the first place. They are removed in this release: + + - `link.tokenState(...)` + - `link.isTokenValid(...)` + - `link.startConnect(...)` + - `link.emailAuth(...)` + - `link.passwordAuth(...)` + - `link.connectManualProvider(...)` + - `team.getLinkConfig(...)` + + The supporting request/body classes that backed these methods are removed alongside them: + + - `BeginLinkTokenRequest` + - `EmailAuthLink` + - `PasswordAuthLink` + - `LinkTokenStateRequest` + - `LinkTokenValidationRequest` + - `ManualConnectionData` + + If you have call sites referencing these methods, see the Junction Link API reference for the documented integration path. +- **Public types removed** — [migration steps](MIGRATION.md#public-types-removed) + Three top-level public types were removed from the SDK with no equivalent. If you imported any of these, drop the import: + + - `AuthType` — was used by the legacy `email_auth` flow only. + - `ManualProviders` — was the parameter type for the now-removed `connectManualProvider` method (one of the legacy link methods, see above). With that method gone, this enum is removed too. + - `ClientFacingUserKey` — the endpoint that used to return this model now returns `ClientFacingUser` instead. If you depended on the user-key shape, switch to reading the user fields off `ClientFacingUser` directly. diff --git a/migration-from-vital/MIGRATION.md b/migration-from-vital/MIGRATION.md new file mode 100644 index 0000000..a46fe2d --- /dev/null +++ b/migration-from-vital/MIGRATION.md @@ -0,0 +1,336 @@ +# Migration guide + +_From `tryVital/vital-java@1.2.588` to the new release._ + +## Install the new package + + + +This is a *replacement* dependency, not a version bump. Update your `build.gradle` (or `pom.xml`) to drop the old coordinate and add the new one, then re-resolve. + +After switching the dependency, every `import com.vital...` line needs to become `import com.junction...` (covered by the package-prefix update below). + +Things to look out for: + +- Aliased dependency declarations in `libs.versions.toml` / `gradle/libs.versions.toml` catalogs. +- Internal repackaged or shaded JARs that bundle the old artifact. +- CI artifact-cache pins, Dockerfile `COPY` lines, and lockfiles (`gradle.lockfile`). +- Documentation, READMEs, and onboarding scripts that quote the old Maven coordinate as a literal string. + +**Before:** + +```groovy +// build.gradle +dependencies { + implementation 'io.tryvital:vital-java:1.2.605' +} +``` + +```xml + + + io.tryvital + vital-java + 1.2.605 + +``` + +**After:** + +```groovy +// build.gradle +dependencies { + implementation 'com.junction:junction-java:1.0.0' +} +``` + +```xml + + + com.junction + junction-java + 1.0.0 + +``` + +## Pick up the new environment URLs + + + +If your code constructs the client with `Environment.PRODUCTION` (or `PRODUCTION_EU`, `SANDBOX`, `SANDBOX_EU`), no change is needed — the constants now point at the new hosts. If your code passes a literal URL or compares response/log strings against an old URL, update each one using the table below: + +| Environment | Before | After | +|-------------------|---------------------------------------|-----------------------------------------| +| Production (US) | `https://api.tryvital.io` | `https://api.us.junction.com` | +| Production (EU) | `https://api.eu.tryvital.io` | `https://api.eu.junction.com` | +| Sandbox (US) | `https://api.sandbox.tryvital.io` | `https://api.sandbox.us.junction.com` | +| Sandbox (EU) | `https://api.sandbox.eu.tryvital.io` | `https://api.sandbox.eu.junction.com` | + +Things to look out for: + +- Outbound-allowlist firewall rules and proxy configurations pinned to the old hostnames. +- Mocked HTTP fixtures (WireMock, MockServer) that reference the old URLs. +- Environment variables that pin a base URL (e.g. `VITAL_BASE_URL`). + +**Before:** + +```java +Vital client = Vital.builder() + .apiKey("...") + .url("https://api.tryvital.io") + .build(); +``` + +**After:** + +```java +Junction client = Junction.builder() + .apiKey("...") + .url("https://api.us.junction.com") + .build(); +``` + +## Update exception and HTTP-response references + + + +Update `catch` clauses, `throws` declarations, and any helper-method signatures or generic bounds that mention `VitalException` or `VitalHttpResponse` to use `JunctionException` and `JunctionHttpResponse` respectively. + +**Before:** + +```java +try { + client.user().get(userId); +} catch (VitalException e) { + log.error("call failed", e); +} + +VitalHttpResponse raw = client.user().withRawResponse().get(userId); +``` + +**After:** + +```java +try { + client.user().get(userId); +} catch (JunctionException e) { + log.error("call failed", e); +} + +JunctionHttpResponse raw = client.user().withRawResponse().get(userId); +``` + +## Update import paths + + + +Replace every `import com.vital...` line in your codebase with `import com.junction...`. The sub-package layout under the new prefix is identical, so only the prefix changes. + +Things to look out for: + +- Fully-qualified class names embedded in strings (reflection, Spring config, logging configs). +- IDE-generated suppression comments referencing the old package. +- `package-info.java` files in any module that wraps or extends SDK types. + +**Before:** + +```java +import com.vital.api.Vital; +import com.vital.api.resources.user.UserClient; +import com.vital.api.resources.user.requests.UserCreateBody; +``` + +**After:** + +```java +import com.junction.api.Junction; +import com.junction.api.resources.user.UserClient; +import com.junction.api.resources.user.requests.UserCreateBody; +``` + +## Update client class names + + + +The entry-point client classes have been renamed across the SDK: + +- `Vital` → `Junction` +- `VitalBuilder` → `JunctionBuilder` +- `AsyncVital` → `AsyncJunction` +- `AsyncVitalBuilder` → `AsyncJunctionBuilder` + +Things to look out for: + +- Field declarations and method-parameter types that hold a typed client reference. +- Test fixtures and DI / Spring beans that wire the client by type. +- Import statements (covered separately by the package-prefix update). + +**Before:** + +```java +import com.vital.api.Vital; + +Vital client = Vital.builder() + .apiKey("...") + .build(); +``` + +**After:** + +```java +import com.junction.api.Junction; + +Junction client = Junction.builder() + .apiKey("...") + .build(); +``` + +## Pass path parameters as positional arguments + + + +For each endpoint with a path parameter: + +- Drop the wrapper request builder and pass the path values directly as method arguments, in the order they appear in the URL template. +- If the endpoint also takes body or query parameters, those still go through a request object — pass it as the next argument after the path values. +- The wrapper request types that previously held only path params are no longer generated; types that hold body/query params remain (with their new verb-first names — see the request-type rename section below). + +**Before:** + +```java +client.user().get( + UserGetRequest.builder() + .userId(userId) + .build() +); +``` + +**After:** + +```java +client.user().get(userId); +``` + +## Update request-type imports to verb-first names + + + +Each per-endpoint request type is renamed so the verb leads. The mechanical rule is: the resource name moves from the front of the class to a suffix. A few representative renames: + +- `LabTestsGetMarkersRequest` → `GetMarkersLabTestsRequest` +- `LinkListBulkOpsRequest` → `ListBulkOpsLinkRequest` +- `LinkGetAllProvidersRequest` → `GetAllProvidersLinkRequest` + +If your code only constructs request objects inline at the call site, this change is invisible. If you import the type by name (for helper-method signatures, custom factories, or annotations), update each reference. + +**Before:** + +```java +import com.vital.api.resources.labtests.requests.LabTestsGetMarkersRequest; + +LabTestsGetMarkersRequest req = LabTestsGetMarkersRequest.builder() + .labId(labId) + .build(); +client.labTests().getMarkers(req); +``` + +**After:** + +```java +import com.junction.api.resources.labtests.requests.GetMarkersLabTestsRequest; + +GetMarkersLabTestsRequest req = GetMarkersLabTestsRequest.builder() + .labId(labId) + .build(); +client.labTests().getMarkers(req); +``` + +## Unwrap nullable getters + + + +For each model field that the API documents as nullable, the getter now returns `Optional`. Update call sites to unwrap explicitly with `.orElse(default)`, `.isPresent()` / `.get()`, or `.ifPresent(...)` depending on how you want to handle missing values. + +Builder setters for the same fields accept `null` (treated as absent) and an `Optional` overload. If you set a previously non-null field with `null`, the builder no longer rejects it; verify the resulting payload still matches the API contract. + +**Before:** + +```java +ClientFacingUser user = client.user().get(userId); +String email = user.getEmail(); +``` + +**After:** + +```java +ClientFacingUser user = client.user().get(userId); +String email = user.getEmail().orElse(null); +``` + +## Handle the unknown-enum sentinel in switch statements + + + +Any `switch` over an enum's `getEnumValue()` should include either a `default` arm or an explicit `_UNKNOWN` case so unrecognised wire values are handled instead of silently falling through. Pattern-matching `instanceof` and equality checks against unknown values now compare to the sentinel rather than throwing. + +**Before:** + +```java +switch (source.getProvider().getEnumValue()) { + case OURA: + handleOura(); + break; + case FITBIT: + handleFitbit(); + break; +} +``` + +**After:** + +```java +switch (source.getProvider().getEnumValue()) { + case OURA: + handleOura(); + break; + case FITBIT: + handleFitbit(); + break; + case _UNKNOWN: + default: + handleUnknown(source.getProvider().toString()); + break; +} +``` + +## Drop calls to the legacy link methods + + + +These methods were deprecated for years and were never part of the documented Junction Link integration. Customer code that didn't reference them needs no migration. If you do have call sites, replace them with the Junction Link integration described in the API reference — there isn't a one-to-one drop-in, the legacy methods wrapped retired endpoints with no published equivalents. + +## Drop imports for removed public types + + + +Three names were exported from the package root in the old SDK but are not present in the new SDK: + +- `AuthType` — was only used by the legacy `emailAuth` flow. +- `ManualProviders` — was the parameter type for the now-removed `connectManualProvider` method. +- `ClientFacingUserKey` — callers should switch to `ClientFacingUser`. The endpoint that previously returned `ClientFacingUserKey` now returns `ClientFacingUser`. + +**Before:** + +```java +import com.vital.api.types.AuthType; +import com.vital.api.types.ManualProviders; +import com.vital.api.types.ClientFacingUserKey; +``` + +**After:** + +```java +// AuthType and ManualProviders have no replacement — drop the imports. +// ClientFacingUserKey -> ClientFacingUser +import com.junction.api.types.ClientFacingUser; +```