npm package: @sanderhurlen/ts-kartverket
Description: A modern TypeScript client library for The Norwegian Mapping Authority (Kartverket) APIs, providing type-safe access to both Matrikkel (Cadastral Registry) and Grunnbok (Land Registry) services.
Latest version: 0.8.0

# @sanderhurlen/ts-kartverket

A modern TypeScript client library for The Norwegian Mapping Authority (Kartverket) APIs, providing type-safe access to both Matrikkel (Cadastral Registry) and Grunnbok (Land Registry) services.

## Features

- 🔒 **Type-safe** - Full TypeScript support with comprehensive type definitions
- 🏗️ **Auto-generated** - Client interfaces generated from official WSDL specifications
- 📦 **Modular** - Separate clients and utilities for Matrikkel and Grunnbok services
- 🛠️ **Utilities** - Built-in helper functions for common operations and data processing
- 🧪 **Tested** - Comprehensive test coverage with real-world examples
- 📋 **Schema validation** - Built-in Zod schemas for runtime data validation and transformation
- 🗂️ **Code lists** - Access to Norwegian administrative and classification codes
- 🌐 **Environment-aware** - Easy configuration management for different environments

## Installation

```bash
npm install @sanderhurlen/ts-kartverket
# or
yarn add @sanderhurlen/ts-kartverket
# or
pnpm add @sanderhurlen/ts-kartverket
```

## Quick Start

### Matrikkel Client (Cadastral Registry)

The Matrikkel client provides access to cadastral data including properties, buildings, addresses, and administrative districts.

```typescript
import {
	MatrikkelClient,
	clientUtilsMatrikkel,
	domene,
} from "@sanderhurlen/ts-kartverket";

// Initialize the client
const client = new MatrikkelClient({
	url: "https://your-matrikkel-url",
	username: "your-username",
	password: "your-password",
});

// Download objects by type with automatic validation
const response = await clientUtilsMatrikkel.lastNedObjekter(client, "Krets", {
	etterId: "85436596",
	maksAntall: 100,
});

// Validate and parse the response
const validatedData = domene.matrikkel.MatrikkelBubbleSchema.array().parse(
	response.return?.item,
);

console.log(validatedData);
```

### Grunnbok Client (Land Registry)

The Grunnbok client provides access to land registry data including ownership, mortgages, and property rights.

```typescript
import {
	GrunnbokClient,
	clientUtilsGrunnbok,
	domene,
} from "@sanderhurlen/ts-kartverket";

// Initialize the client
const client = new GrunnbokClient({
	url: "https://your-grunnbok-url",
	username: "your-username",
	password: "your-password",
});

// Find register unit IDs by cadastral numbers
const registerUnitIds =
	await clientUtilsGrunnbok.findRegisterenhetIdsForMatrikkelnummerIdents(
		client,
		[
			{
				kommunenummer: "0301",
				gaardsnummer: 212,
				bruksnummer: 8,
				festenummer: 0,
			},
		],
	);

// Validate the response
const validatedIds =
	domene.grunnbok.GrunnbokBubbleSchema.array().parse(registerUnitIds);

console.log(validatedIds);
```

## Available Data Types

### Matrikkel (Cadastral Data)

- **Addresses** (`Adresse`) - Street addresses and cadastral addresses with geographic coordinates
- **Buildings** (`Bygg`) - Building information, modifications, and usage units
- **Properties** (`Matrikkelenhet`) - Land parcels, property units, and ownership information
- **Administrative Districts** (`Krets`) - Various administrative boundaries and postal areas
- **Cultural Heritage** (`Kulturminne`) - Protected cultural sites and monuments
- **Usage Units** (`Bruksenhet`) - Individual units within buildings (apartments, offices, etc.)
- **Persons** (`Person`) - Legal entities, individuals, and organizations
- **Roads** (`Veg`) - Road and street information with addressing data

### Grunnbok (Land Registry Data)

- **Register Units** (`Registerenhet`) - Property ownership records and legal descriptions
- **Ownership Rights** (`Eiendomsrett`) - Legal ownership information and shares
- **Mortgages** (`Pantedokument`) - Mortgage and lien information with amounts and terms
- **Rights and Restrictions** (`Rettsstiftelse`) - Easements, servitudes, and other property rights
- **Documents** (`Dokument`) - Legal documents and their registration information
- **Municipalities** (`Kommune`) - Municipal boundaries and administrative information

## Client Utilities

### Matrikkel Utilities

```typescript
import { clientUtilsMatrikkel } from "@sanderhurlen/ts-kartverket";

// Download objects by domain and ID
const buildings = await clientUtilsMatrikkel.lastNedObjekter(client, "Bygg", {
	etterId: "123456",
	maksAntall: 50,
});

// Get latest changes by ID with pagination
const changes = await clientUtilsMatrikkel.getLatestChangeById(client, 123456, {
	maksAntall: 10,
});

// Download objects with custom filters
const properties = await clientUtilsMatrikkel.lastNedObjekter(
	client,
	"Matrikkelenhet",
	{
		etterId: "987654",
		maksAntall: 25,
		// Additional filter options supported
	},
);
```

### Grunnbok Utilities

```typescript
import { clientUtilsGrunnbok } from "@sanderhurlen/ts-kartverket";

// Find register units by various identifier types
const registerUnits = await clientUtilsGrunnbok.findRegisterenhetIdsForIdents(
	client,
	identifiers,
);

// Find register units by cadastral numbers
const cadastralUnits =
	await clientUtilsGrunnbok.findRegisterenhetIdsForMatrikkelnummerIdents(
		client,
		[
			{
				kommunenummer: "0301",
				gaardsnummer: 212,
				bruksnummer: 8,
				festenummer: 0,
			},
			{
				kommunenummer: "0301",
				gaardsnummer: 213,
				bruksnummer: 1,
				festenummer: 0,
			},
		],
	);

// Find register units by organization numbers
const orgUnits =
	await clientUtilsGrunnbok.findRegisterenhetIdsForOrganisasjonnummerIdents(
		client,
		["123456789", "987654321"],
	);
```

## Schema Validation & Type Safety

The package includes comprehensive Zod schemas for runtime validation and TypeScript types for compile-time safety:

```typescript
import { domene } from "@sanderhurlen/ts-kartverket";
import { z } from "zod";

// Access domain schemas
const { matrikkel, grunnbok } = domene;

// Validate Matrikkel data with automatic type inference
const matrikkelData = matrikkel.MatrikkelBubbleSchema.parse(rawData);
// Type: MatrikkelBubble (automatically inferred)

// Validate Grunnbok data
const grunnbokData = grunnbok.GrunnbokBubbleSchema.parse(rawData);
// Type: GrunnbokBubble (automatically inferred)

// Access specific schemas for individual entity types
const addressSchema = matrikkel.AdresseSchema;
const buildingSchema = matrikkel.ByggSchema;
const propertySchema = matrikkel.MatrikkelenhetSchema;

// Validate specific entity types
const address = addressSchema.parse(addressData);
const building = buildingSchema.parse(buildingData);

// Use safe parsing for error handling
const result = matrikkel.MatrikkelBubbleSchema.safeParse(uncertainData);
if (result.success) {
	console.log("Valid data:", result.data);
} else {
	console.error("Validation errors:", result.error.errors);
}
```

## Advanced Error Handling

```typescript
import { z } from "zod";
import {
	MatrikkelClient,
	clientUtilsMatrikkel,
	domene,
} from "@sanderhurlen/ts-kartverket";

async function fetchAndValidateData() {
	try {
		const response = await clientUtilsMatrikkel.lastNedObjekter(
			client,
			"Krets",
		);

		// Validate the response data
		const validatedData = domene.matrikkel.MatrikkelBubbleSchema.array().parse(
			response.return?.item,
		);

		return validatedData;
	} catch (error) {
		if (error instanceof z.ZodError) {
			console.error("Data validation failed:");
			error.errors.forEach((err) => {
				console.error(`  - ${err.path.join(".")}: ${err.message}`);
			});
		} else if (error instanceof Error) {
			console.error("API call failed:", error.message);
		} else {
			console.error("Unknown error:", error);
		}
		throw error;
	}
}
```

## Environment Configuration

### Using Environment Variables

Create a `.env` file in your project root:

```env
# Matrikkel (Cadastral Registry) Configuration
MATRIKKEL_URL=https://your-matrikkel-endpoint
MATRIKKEL_USERNAME=your-username
MATRIKKEL_PASSWORD=your-password

# Grunnbok (Land Registry) Configuration
GRUNNBOK_URL=https://your-grunnbok-endpoint
GRUNNBOK_USERNAME=your-username
GRUNNBOK_PASSWORD=your-password
```

### Using Configuration Objects

```typescript
import { MatrikkelClient, GrunnbokClient } from "@sanderhurlen/ts-kartverket";

// Load environment variables
process.loadEnvFile(".env");

// Initialize clients with environment variables
const matrikkelClient = new MatrikkelClient({
	url: process.env.MATRIKKEL_URL!,
	username: process.env.MATRIKKEL_USERNAME!,
	password: process.env.MATRIKKEL_PASSWORD!,
});

const grunnbokClient = new GrunnbokClient({
	url: process.env.GRUNNBOK_URL!,
	username: process.env.GRUNNBOK_USERNAME!,
	password: process.env.GRUNNBOK_PASSWORD!,
});
```

## Code Lists & Classification Codes

Access Norwegian administrative and classification codes directly:

```typescript
import {
	kodelisteMatrikkel,
	kodelisteGrunnbok,
} from "@sanderhurlen/ts-kartverket";

// Access Matrikkel code lists
const municipalities = kodelisteMatrikkel.kommuner;
const buildingTypes = kodelisteMatrikkel.bygningstyper;
const addressTypes = kodelisteMatrikkel.adressetyper;

// Access Grunnbok code lists
const documentTypes = kodelisteGrunnbok.dokumenttyper;
const rightTypes = kodelisteGrunnbok.rettighetstyper;

// Use code lists for validation or display
console.log("Available municipalities:", municipalities);
console.log("Building type codes:", buildingTypes);
```

## Examples

### Complete Matrikkel Example

```typescript
import {
	MatrikkelClient,
	clientUtilsMatrikkel,
	domene,
	kodelisteMatrikkel,
} from "@sanderhurlen/ts-kartverket";

async function fetchPropertyData() {
	// Initialize client
	const client = new MatrikkelClient({
		url: process.env.MATRIKKEL_URL!,
		username: process.env.MATRIKKEL_USERNAME!,
		password: process.env.MATRIKKEL_PASSWORD!,
	});

	try {
		// Fetch building data
		const buildingResponse = await clientUtilsMatrikkel.lastNedObjekter(
			client,
			"Bygg",
			{
				etterId: "123456",
				maksAntall: 10,
			},
		);

		// Validate and process the data
		const buildings = domene.matrikkel.MatrikkelBubbleSchema.array().parse(
			buildingResponse.return?.item,
		);

		// Process each building
		buildings.forEach((building) => {
			if (building._type === "Bygning") {
				console.log(`Building ID: ${building.id}`);
				console.log(`Building Type: ${building.bygningstype}`);

				// Use code lists for human-readable descriptions
				const typeDescription =
					kodelisteMatrikkel.bygningstyper[building.bygningstype];
				console.log(`Type Description: ${typeDescription}`);
			}
		});

		return buildings;
	} catch (error) {
		console.error("Failed to fetch property data:", error);
		throw error;
	}
}
```

### Complete Grunnbok Example

```typescript
import {
	GrunnbokClient,
	clientUtilsGrunnbok,
	domene,
} from "@sanderhurlen/ts-kartverket";

async function fetchOwnershipData() {
	// Initialize client
	const client = new GrunnbokClient({
		url: process.env.GRUNNBOK_URL!,
		username: process.env.GRUNNBOK_USERNAME!,
		password: process.env.GRUNNBOK_PASSWORD!,
	});

	try {
		// Find properties by cadastral numbers
		const propertyIds =
			await clientUtilsGrunnbok.findRegisterenhetIdsForMatrikkelnummerIdents(
				client,
				[
					{
						kommunenummer: "0301", // Oslo
						gaardsnummer: 212,
						bruksnummer: 8,
						festenummer: 0,
					},
				],
			);

		// Validate the response
		const validatedIds =
			domene.grunnbok.GrunnbokBubbleSchema.array().parse(propertyIds);

		console.log(`Found ${validatedIds.length} properties`);

		return validatedIds;
	} catch (error) {
		console.error("Failed to fetch ownership data:", error);
		throw error;
	}
}
```

## API Reference

### Client Initialization

#### MatrikkelClient

```typescript
const client = new MatrikkelClient(config: ClientConfig)
```

#### GrunnbokClient

```typescript
const client = new GrunnbokClient(config: ClientConfig)
```

#### ClientConfig

```typescript
interface ClientConfig {
	url: string; // API endpoint URL
	username: string; // Authentication username
	password: string; // Authentication password
}
```

### Client Utilities

#### clientUtilsMatrikkel

- `lastNedObjekter(client, domain, options)` - Download objects by type
- `getLatestChangeById(client, id, options)` - Get latest changes for an object

#### clientUtilsGrunnbok

- `findRegisterenhetIdsForIdents(client, identifiers)` - Find by various identifiers
- `findRegisterenhetIdsForMatrikkelnummerIdents(client, cadastralNumbers)` - Find by cadastral numbers
- `findRegisterenhetIdsForOrganisasjonnummerIdents(client, orgNumbers)` - Find by organization numbers

## Requirements

- **Node.js** >= 18.0.0
- **TypeScript** >= 5.0.0 (for TypeScript projects)
- **Modern ES modules** support

## Development & Contributing

### Local Development

```bash
# Install dependencies
pnpm install

# Generate client interfaces from WSDL
pnpm run generate-clients

# Build the package
pnpm run build

# Run tests
pnpm run test

# Type checking
pnpm run check-types
```

### Project Structure

```
packages/client/
├── src/
│   ├── clients/          # Generated SOAP clients
│   ├── grunnbok/         # Grunnbok-specific utilities
│   ├── matrikkel/        # Matrikkel-specific utilities
│   ├── factory.ts        # Client factory functions
│   ├── kodeliste.ts      # Norwegian code lists
│   └── index.ts          # Main exports
├── examples/             # Usage examples
├── resources/            # WSDL files and schemas
└── scripts/              # Build and generation scripts
```

## License

MIT - see [LICENSE](../../LICENSE) file for details.

## Links

- [NPM Package](https://www.npmjs.com/package/@sanderhurlen/ts-kartverket)
- [Kartverket Official Documentation](https://www.kartverket.no/)
- [API Documentation](https://ws.geonorge.no/)
- [GitHub Repository](https://github.com/sanderhurlen/ts-kartverket)
- [Domain Schema Package](https://github.com/sanderhurlen/ts-kartverket/tree/main/packages/domain)

## Support

For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/sanderhurlen/ts-kartverket) or open an issue.