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..520d13b --- /dev/null +++ b/migration-from-vital/CHANGELOG.md @@ -0,0 +1,112 @@ +# Changelog + +_Major release. Baseline: `tryVital/vital-node@3.1.544`._ + +## Breaking changes + +- **Package renamed: @tryvital/vital-node to @junction-api/sdk** — [migration steps](MIGRATION.md#install) + The published npm package has been renamed from `@tryvital/vital-node` to `@junction-api/sdk`. Uninstall the old package and install the new one. This is a replacement, not a version bump — there is no overlap window where both packages publish the same release. After installing the new package, update every import to point at `@junction-api/sdk` and update the imported symbols per the rename sections below. +- **Namespace export renamed: Vital to Junction** — [migration steps](MIGRATION.md#rename-namespace-export) + The package's namespace alias has changed from `Vital` to `Junction`. Code that does `import { Vital } from "@tryvital/vital-node"` (or `import * as Vital from ...`) and references types as `Vital.SomeType` must switch to `Junction` and `Junction.SomeType`. +- **Top-level client class renamed: VitalClient to JunctionClient** — [migration steps](MIGRATION.md#rename-client-class) + The default exported client class has been renamed from `VitalClient` to `JunctionClient`. Update every `new VitalClient(...)` construction site and every type annotation that references `VitalClient`. +- **Server base URLs replaced (Environment enum also renamed)** — [migration steps](MIGRATION.md#rename-environment-enum) + The SDK's server base URLs have been replaced as part of the rebrand: + + - `api.tryvital.io` → `api.us.junction.com` + - `api.eu.tryvital.io` → `api.eu.junction.com` + - `api.sandbox.tryvital.io` → `api.sandbox.us.junction.com` + - `api.sandbox.eu.tryvital.io` → `api.sandbox.eu.junction.com` + + The environment enum has also been renamed: + + - `VitalEnvironment` → `JunctionEnvironment` + + If you pass an environment value through the enum (e.g. `JunctionEnvironment.Production`), the new URL is picked up automatically once you switch to the renamed enum. If you pass a literal URL string into the client `environment` option, you must update the string yourself. +- **Error classes renamed** — [migration steps](MIGRATION.md#rename-error-classes) + The thrown error classes have been renamed: + + - `VitalError` → `JunctionError` + - `VitalTimeoutError` → `JunctionTimeoutError` + + Update `catch` blocks and `instanceof` checks. Both classes are still re-exported from the package root. +- **Path parameters are now inline on the request object** — [migration steps](MIGRATION.md#inline-path-parameters) + Methods that previously accepted a positional path-parameter argument followed by a request object now take a single request object containing the path-parameter fields. For example: + + ```typescript + // Before + client.labTests.bookPhlebotomyAppointment("order_id", { bookingKey: "..." }); + + // After + client.labTests.bookPhlebotomyAppointment({ orderId: "order_id", body: { bookingKey: "..." } }); + ``` + + Methods that already took only a request object are unaffected. +- **Per-endpoint request types renamed to read verb-first** — [migration steps](MIGRATION.md#verb-first-request-types) + Generated per-endpoint request interface names have been reordered so the verb leads, e.g. `LabTestsGetOrdersRequest` is now `GetOrdersLabTestsRequest` and `LabTestsGetRequest` is now `GetLabTestsRequest`. Most callers pass an object literal and never name these types, but if you import them for explicit type annotations on helper functions, you must update the type names. +- **File-download responses return a Web Response wrapper** — [migration steps](MIGRATION.md#binary-response) + Endpoints that download binary content (PDFs, raw lab files) now resolve to a `core.BinaryResponse` object with Web-platform methods: `arrayBuffer()`, `blob()`, `bytes()`, and `stream()` (which returns a Web `ReadableStream`). Code that previously called `.pipe()`, `.toString()`, or otherwise treated the body as a Node `Buffer` or `Readable` must read it through one of these methods. +- **Node 18+ required at runtime** — [migration steps](MIGRATION.md#node-18-runtime) + The SDK now relies on the platform's native `fetch` and `FormData` globals. Node 16 and earlier are no longer supported. The previously bundled `node-fetch` runtime dependency and the Node-16 multipart shim have been removed. If you run on Node 16, upgrade to Node 18 LTS (or newer) before adopting this release. + +## New & improved + +- **New top-level resources: lab accounts, order transactions, compendium search** + The SDK now exposes three new top-level resource modules: + + - `client.labAccount` — read your team's lab accounts (`getTeamLabAccounts`). + - `client.orderTransaction` — fetch the consolidated order-transaction view (`getTransaction`). + - `client.compendium` — convert and search lab-test compendium entries (`convert`, `search`). + + Accompanying model types appear under the namespace export (`Junction.ClientFacingLabAccount`, `Junction.ClientFacingOrderTransaction`, `Junction.ConvertCompendiumResponse`, etc.). See the API reference for endpoint details. +- **Inline anonymous types in method signatures** — [migration steps](MIGRATION.md#inline-types) + Method signatures and IDE hovers now show inline object types instead of named imports for many anonymous shapes. The named types are still exported, so existing imports continue to compile; the change is mostly visible when reading hover docs. +- **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. +- **Client-scoped passthrough fetch** + The client now exposes a `fetch` method that proxies a Web-style fetch call through the same auth provider, base URL, and default headers configured on the client. Use it to call endpoints the SDK does not yet model, without re-implementing auth and URL handling. + + ```ts + const res = await client.fetch("/v3/some/new/endpoint", { method: "GET" }); + const data = await res.json(); + ``` +- **Optional fields now reflect API nullability** — [migration steps](MIGRATION.md#respect-nullable) + Fields that the API marks as nullable are now typed as nullable/optional in TypeScript, matching what you actually receive on the wire. Existing code that already accounted for missing fields keeps working; code that assumed non-nullable values may need a guard or non-null assertion in places where the new typing surfaces a possible `null`. +- **Corepack-aware packageManager field** + The published `package.json` declares `packageManager: pnpm@10.x`. Repos using Corepack will automatically switch to pnpm when running scripts in this package's directory. Consumers using npm or yarn directly remain unaffected; CI configs that pin a specific package manager via Corepack enforcement may need to opt out for this dependency. + +## Removed + +- **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. +- **Legacy link methods removed** — [migration steps](MIGRATION.md#link-legacy-removed) + 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.emailAuth` + - `link.passwordAuth` + - `link.startConnect` + - `link.connectManualProvider` + - `link.tokenState` + - `link.isTokenValid` + + The supporting request/body classes that backed these methods are removed alongside them: + + - `BeginLinkTokenRequest` + - `EmailAuthLink` + - `PasswordAuthLink` + - `LinkTokenValidationRequest` + - `ManualConnectionData` + + If you have call sites referencing these methods, see the Junction Link API reference for the documented integration path. diff --git a/migration-from-vital/MIGRATION.md b/migration-from-vital/MIGRATION.md new file mode 100644 index 0000000..9b0dccd --- /dev/null +++ b/migration-from-vital/MIGRATION.md @@ -0,0 +1,345 @@ +# Migration guide + +_From `tryVital/vital-node@3.1.544` to the new release._ + +## Install the new package + + + +This is a *replacement*, not a version bump — there is no shared release line between the old and new packages. Uninstall the old package, install the new one, and update every import to reference `@junction-api/sdk`. + +Things to look out for: + +- Aliased imports (`import { VitalClient as Client } from "@tryvital/vital-node"`). +- Sub-path imports (`import { ... } from "@tryvital/vital-node/serialization"`, `/link`, `/labTests`, etc.) — the new package keeps the same sub-paths, only the root changes. +- Lockfile pins (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`), Dockerfile install commands, and CI cache keys that reference the old package name. +- Environment variables or config flags that follow the old brand (e.g. `VITAL_API_KEY`) — these are application-level and stay as-is unless you rename them yourself. + +**Before:** + +```bash +npm install @tryvital/vital-node +``` + +```typescript +import { VitalClient } from "@tryvital/vital-node"; +``` + +**After:** + +```bash +npm uninstall @tryvital/vital-node +npm install @junction-api/sdk +``` + +```typescript +import { JunctionClient } from "@junction-api/sdk"; +``` + +## Rename `Vital` namespace to `Junction` + + + +All model types that were exposed under the `Vital` namespace are now under `Junction`. The model class names themselves are unchanged — only the namespace prefix changes. Watch for: + +- Aliased namespace imports (`import * as V from ...`) — if already aliased, no source change is required. +- Type-only references in JSDoc / TSDoc comments, which the TypeScript compiler does not flag. + +**Before:** + +```typescript +import * as Vital from "@tryvital/vital-node"; + +function handle(test: Vital.ClientFacingLabTest) { + // ... +} +``` + +**After:** + +```typescript +import * as Junction from "@junction-api/sdk"; + +function handle(test: Junction.ClientFacingLabTest) { + // ... +} +``` + +## Rename `VitalClient` to `JunctionClient` + + + +Update every construction site, type annotation, and re-export of the client class. Watch for: + +- Aliased imports (`import { VitalClient as Client } from ...`). +- Type-only imports (`import type { VitalClient } from ...`). +- The associated namespace (`VitalClient.Options`) — the namespace was renamed alongside the class, so `VitalClient.Options` is now `JunctionClient.Options`. + +**Before:** + +```typescript +import { VitalClient } from "@tryvital/vital-node"; + +const client = new VitalClient({ apiKey: process.env.API_KEY! }); +``` + +**After:** + +```typescript +import { JunctionClient } from "@junction-api/sdk"; + +const client = new JunctionClient({ apiKey: process.env.API_KEY! }); +``` + +## Update server base URLs (and `Environment` enum name) + + + +The four base URLs are replaced as follows: + +| Old host | New host | +|--------------------------------|-----------------------------------| +| `api.tryvital.io` | `api.us.junction.com` | +| `api.eu.tryvital.io` | `api.eu.junction.com` | +| `api.sandbox.tryvital.io` | `api.sandbox.us.junction.com` | +| `api.sandbox.eu.tryvital.io` | `api.sandbox.eu.junction.com` | + +The environment enum has also been renamed: + +- `VitalEnvironment` → `JunctionEnvironment` + +If you use the enum (`JunctionEnvironment.Production`, etc.), the new URL is picked up automatically because the enum's value changed alongside the rename. If you pass a literal URL string into the `environment` option, replace the host directly. + +**Before:** + +```typescript +import { VitalClient, VitalEnvironment } from "@tryvital/vital-node"; + +const client = new VitalClient({ + apiKey: process.env.API_KEY!, + environment: VitalEnvironment.Production, // "https://api.tryvital.io" +}); +``` + +**After:** + +```typescript +import { JunctionClient, JunctionEnvironment } from "@junction-api/sdk"; + +const client = new JunctionClient({ + apiKey: process.env.API_KEY!, + environment: JunctionEnvironment.Production, // "https://api.us.junction.com" +}); +``` + +## Rename error classes + + + +Update both `instanceof` checks and any `catch (err: VitalError)` annotations. Watch for: + +- Custom error reporters that match by class-name string. +- Subclasses of `VitalError` defined in your own code. + +**Before:** + +```typescript +import { VitalError, VitalTimeoutError } from "@tryvital/vital-node"; + +try { + await client.user.create({ clientUserId: "abc" }); +} catch (err) { + if (err instanceof VitalTimeoutError) { + // ... + } else if (err instanceof VitalError) { + // ... + } +} +``` + +**After:** + +```typescript +import { JunctionError, JunctionTimeoutError } from "@junction-api/sdk"; + +try { + await client.user.create({ clientUserId: "abc" }); +} catch (err) { + if (err instanceof JunctionTimeoutError) { + // ... + } else if (err instanceof JunctionError) { + // ... + } +} +``` + +## Move path parameters onto the request object + + + +For every method that previously took a positional path parameter (`id: string`, `orderId: string`, etc.), move that value onto the request object using its camelCase field name. The previous body argument moves under a `body` field on the same request object. Methods that already took only a request object are unaffected. + +**Before:** + +```typescript +await client.labTests.bookPhlebotomyAppointment("order_id", { + bookingKey: "booking_key", +}); +``` + +**After:** + +```typescript +await client.labTests.bookPhlebotomyAppointment({ + orderId: "order_id", + body: { bookingKey: "booking_key" }, +}); +``` + +## Update request type imports if you reference them by name + + + +The class-name change follows a fixed pattern: `Request` becomes `Request`. For example: + +- `UserCreateRequest` → `CreateUserRequest` +- `LabTestsGetByIdRequest` → `GetByIdLabTestsRequest` +- `LabTestsGetOrdersRequest` → `GetOrdersLabTestsRequest` + +If you only ever pass object literals to client methods, you do not need to update anything — the SDK accepts the same field names on the new types. + +**Before:** + +```typescript +import type { LabTestsGetOrdersRequest } from "@tryvital/vital-node"; + +function list(req: LabTestsGetOrdersRequest) { + // ... +} +``` + +**After:** + +```typescript +import type { GetOrdersLabTestsRequest } from "@junction-api/sdk"; + +function list(req: GetOrdersLabTestsRequest) { + // ... +} +``` + +## Read file-download responses through the Web `Response` wrapper + + + +The returned `core.BinaryResponse` exposes `arrayBuffer()`, `blob()`, `bytes()`, and `stream()` — the same surface as a Web `Response`. Code that previously called `.pipe()`, `.toString()`, or otherwise treated the body as a Node `Buffer` or `Readable` must read it through one of these methods. To pipe into a Node writable stream, convert with `Writable.toWeb` (Node 18+). + +**Before:** + +```typescript +const pdfStream = await client.labTests.getResultPdf(orderId); +pdfStream.pipe(fs.createWriteStream("result.pdf")); +``` + +**After:** + +```typescript +const pdf = await client.labTests.getResultPdf({ orderId }); +const bytes = new Uint8Array(await pdf.arrayBuffer()); +fs.writeFileSync("result.pdf", bytes); + +// or pipe through the Web Streams API: +// pdf.stream()?.pipeTo(Writable.toWeb(fs.createWriteStream("result.pdf"))); +``` + +## Run on Node 18 or newer + + + +Bump your runtime (and CI matrix) to Node 18 LTS or newer. The SDK no longer pins `node-fetch` or a multipart polyfill, so older Node versions will fail at the first network call. Browser and modern serverless runtimes (Cloudflare Workers, Deno, Bun) that already provide global `fetch` and `FormData` work without additional setup. + +**Before:** + +```json +// package.json +{ + "engines": { "node": ">=16" } +} +``` + +**After:** + +```json +// package.json +{ + "engines": { "node": ">=18" } +} +``` + +## Inline anonymous types in method signatures (no source changes) + + + +This is a documentation/hover-only change — your source code does not need to change. If you previously imported a named type for explicit annotations, the import still works; only the IDE hover representation differs. + +**Before:** + +```typescript +// Hovering a method showed a named import like Junction.LabTestsGetByIdRequest +``` + +**After:** + +```typescript +// Hover now shows the object literal { labTestId: string; ... } inline +``` + +## Handle nullable fields where the API admits them + + + +Wherever the API documents a field as nullable, the TypeScript type now reflects that and the compiler will require an explicit guard or non-null assertion. Most call sites only need an optional-chain (`?.`) at the access point. + +**Before:** + +```typescript +const lab = await client.labTests.getById({ labTestId }); +console.log(lab.description.toUpperCase()); +``` + +**After:** + +```typescript +const lab = await client.labTests.getById({ labTestId }); +console.log(lab.description?.toUpperCase()); +``` + +## 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:** + +```typescript +import { Vital, AuthType, ManualProviders, ClientFacingUserKey } from "@tryvital/vital-node"; +``` + +**After:** + +```typescript +// AuthType and ManualProviders have no replacement — drop the imports. +// ClientFacingUserKey -> ClientFacingUser +import { Junction, ClientFacingUser } from "@junction-api/sdk"; +``` + +## 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.