<!-- Source: https://docs.geopera.com/api-reference/sdks/typescript/versioning · Markdown for LLMs -->

# Versioning

`@geopera/sdk` follows Semantic Versioning, and its package version is deliberately independent of the API version carried in the `/v1` path prefix — the two move on their own schedules, and you should never assume they match.

## Two version numbers, two meanings

When you depend on `@geopera/sdk` there are two distinct version numbers in play. Conflating them is the most common source of confusion, so it is worth fixing them in your mind up front.

| Number              | Where it lives           | Current value | What it describes                          | Cadence                         |
| ------------------- | ------------------------ | ------------- | ------------------------------------------ | ------------------------------- |
| Package version     | `package.json` `version` | `2.1.0`       | A release of the npm client                | SemVer, moves often             |
| API surface version | URL path prefix          | `/v1`         | The calling convention for every operation | Changes only on a surface break |

The **package version** describes a client release. It moves whenever the npm package changes — a runtime fix, a new typed operation flowing in from an updated contract, a typing correction, a dependency bump. You select it with npm (`@geopera/sdk@2.1.0`, `@geopera/sdk@^2.1.0`, `@geopera/sdk@latest`).

The **API surface version** lives in the path prefix. Every operation is invoked as `POST /v1/op/{operation_id}` against `https://api.geopera.com` (overridable via the `baseUrl` client option). The SDK targets `/v1`; it does not pin or send a separate spec version in a header, query string, or body field — `/v1` is structural, baked into the URL of every request. See [Concepts](/api-reference/concepts) and [Operations](/api-reference/operations).

These two numbers are decoupled on purpose. The `/v1` segment is a coarse, long-lived contract marker; the package number moves much faster, advancing through many patch and minor releases while `/v1` stays put, because nearly all contract changes are additive and do not break the calling convention. For the full cross-client picture — including the Python client and the CLI — see the API-wide [Versioning](/api-reference/versioning) page.

## How the package uses SemVer

The package follows [Semantic Versioning](https://semver.org): `MAJOR.MINOR.PATCH`.

- **PATCH** (`2.1.x`) — backward-compatible fixes with no surface change: build fixes, typing corrections, dependency bumps, runtime bug fixes. Safe to take automatically.
- **MINOR** (`2.x.0`) — backward-compatible additions, typically new typed operations or new optional fields flowing in from an updated API contract. Existing code keeps compiling and running unchanged; the new surface is simply available.
- **MAJOR** (`x.0.0`) — a breaking change to the package's own public API: a renamed namespace or method, a changed input/output type, a dropped export, or adoption of a breaking contract change. Read the changelog and re-run your typecheck before upgrading.

Because operation inputs and outputs are fully typed, an upgrade that changes an operation's body or response shows up at compile time. Run `tsc --noEmit` after upgrading and every affected call site surfaces immediately as a type error rather than failing at runtime:

```bash
npm install @geopera/sdk@latest
npx tsc --noEmit
```

This is the single most useful property of the typed client during an upgrade: the type checker is your migration checklist.

## What "breaking" means for the package version

A package MAJOR bump signals a change to the client surface you write against. Concretely, any of these triggers a major release:

- A namespace or method is renamed or removed (for example `client.catalog.search` moving or changing shape).
- A typed input or output model gains a required field, drops a field, or changes a field's type in a backward-incompatible way.
- A top-level export is renamed or removed (for example `GeoperaClient`, `GeoperaError`, `callOperation`, `DEFAULT_BASE_URL`, or an exported type such as `GeoperaClientOptions` or `OperationId`).
- The client adopts a breaking change in the underlying API contract.

Additive changes — a new operation, a new optional input field, a new field on a response, a new enum value — are **minor**, not major. They cannot break code that compiled against the previous version, so they never force a major bump.

## What "breaking" means for the `/v1` surface

The `/v1` segment is the most stable thing in the API. It changes only for a surface-incompatible break — a change to the calling convention shared by _all_ operations, such as the request method or path shape (moving away from `POST /v1/op/{id}`), the authentication model (see [Authentication](/api-reference/sdks/typescript/authentication)), the error envelope (see [Errors](/api-reference/sdks/typescript/errors)), or the shared pagination or idempotency contract (see [Pagination](/api-reference/pagination) and [Idempotency](/api-reference/idempotency)).

If such a break ever ships, it arrives at a new prefix (`/v2/op/...`) and `/v1` continues to serve existing clients in parallel. You will never have an existing `/v1` request silently change shape underneath you. A future `/v2` surface would ship as a new major of `@geopera/sdk` that targets the new prefix; until then, every release of the package keeps speaking `/v1`.

The two breaking definitions are independent. A package major can ship without any `/v1` change (for example, renaming a method for ergonomics). And a `/v1 → /v2` surface break would necessarily come with a package major, but the reverse does not hold.

## Installing and upgrading

Always install the published package from npm. The package is `@geopera/sdk`; it is ESM-first with a CommonJS fallback and requires Node 18 or newer.

```bash
npm install @geopera/sdk
# or: pnpm add @geopera/sdk
# or: yarn add @geopera/sdk
```

Upgrade to the latest release and re-run your typecheck:

```bash
npm install @geopera/sdk@latest
npx tsc --noEmit
```

Pin an exact version when you want fully reproducible installs (your lockfile already does this; an exact spec in `package.json` makes it explicit):

```bash
npm install @geopera/sdk@2.1.0
```

## Choosing a version range

Pin the package the way you pin any dependency: allow minors and patches, cap the major, and upgrade across a major deliberately after reading the changelog.

```bash
# Allow 2.1.0 up to (but not including) 3.0.0 — recommended
npm install @geopera/sdk@^2.1.0
```

The caret range `^2.1.0` resolves to the newest `2.x.y` and refuses `3.0.0`, so you automatically receive new operations and fixes while staying behind any breaking major. If you need tighter control during a freeze, a tilde range pins to patch level:

```bash
# Allow only 2.1.x patches
npm install @geopera/sdk@~2.1.0
```

Expressed directly in `package.json`:

```json
{
	"dependencies": {
		"@geopera/sdk": "^2.1.0"
	}
}
```

## Reading the version at runtime

The version you actually resolved is recorded in your lockfile and queryable from the toolchain. Use these rather than hard-coding a number in your application:

```bash
# The version installed in this project
npm ls @geopera/sdk

# The latest version published to npm
npm view @geopera/sdk version

# Every published version, to see the release history
npm view @geopera/sdk versions
```

If you need the version inside a Node program (for example to include it in a support log), read it from the package's own manifest rather than maintaining a separate constant:

```typescript
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const { version } = require('@geopera/sdk/package.json');

console.log(`@geopera/sdk ${version}`); // -> @geopera/sdk 2.1.0
```

## Worked example: a new operation flows through

Suppose the API gains a new operation. Here is how each version number responds, so you can see why the package version moves but `/v1` does not.

1. **`/v1` surface** — unchanged. The new operation is invoked at `POST /v1/op/...` exactly like every existing one. Adding an operation is additive.
2. **`@geopera/sdk`** — released as a **minor** bump (for example `2.1.0 → 2.2.0`). The new operation appears as a typed namespace method; existing code is untouched.
3. **Your code** — keeps compiling and running. To _use_ the new operation you bump the dependency within your `^2.x` range; you never change `baseUrl` or the path prefix.

```typescript
import { GeoperaClient } from '@geopera/sdk';

const client = new GeoperaClient({ token: 'gpra_...' });

// Existing call — identical before and after the upgrade.
const results = await client.catalog.search({
	collections: ['sentinel-2-l2a'],
	limit: 10
});
```

The escape hatch behaves the same way across versions. `client.invoke("catalog.search", body)` dispatches to `POST /v1/op/catalog.search` regardless of which `2.x` package you are on; a new operation just becomes a new valid `OperationId` literal once you upgrade.

## Changelog

Release notes for each version are published with the package and in the source repository. Check the changelog before any major upgrade to see which namespaces, methods, or types changed.

- Release notes and tags: [`geo-pera/geopera-typescript`](https://github.com/geo-pera/geopera-typescript) on GitHub.
- Published versions and metadata: [`@geopera/sdk`](https://www.npmjs.com/package/@geopera/sdk) on npm.

Watch the package changelog rather than the API's spec version — the changelog is where breaking-vs-additive is called out for _this_ client specifically. For the relationship between this package, the `geopera` Python client, the CLI, and the `/v1` surface, see the API-wide [Versioning](/api-reference/versioning) page.

## Guidance

- Build against `/v1` and treat it as permanent for the life of your integration; a successor surface would ship at a new prefix and a new package major, never replace `/v1` in place.
- Pin with `^2.1.0` (minors and patches allowed, major capped), commit your lockfile, and upgrade across a major deliberately.
- Run `tsc --noEmit` after every upgrade — the typed client turns contract changes into compile errors at your call sites.
- Keep the two numbers separate in your head: the package SemVer (`2.1.0`) and the API surface (`/v1`) move independently.

See [Operations](/api-reference/operations) and the [TypeScript quickstart](/api-reference/sdks/typescript/quickstart) for usage, and [Client reference](/api-reference/sdks/typescript/client-reference) for the exported surface that SemVer protects.
