npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@transit-se/sdk

v1.1.0

Published

TypeScript SDK for Swedish public transit APIs (Trafiklab, GTFS-RT). Departures, stop lookups, service alerts, vehicle positions, and more.

Readme

@transit-se/sdk

TypeScript SDK for Trafiklab realtime APIs with a focus on Stockholm (SL).

Also available as AI-callable tools via @transit-se/mcp.

Table of Contents

Installation

npm install @transit-se/sdk

APIs Covered

| API | Auth | Scope | | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- | --------- | | SL Transport | None | Stockholm | | SL Deviations | None | Stockholm | | Trafiklab Stop Lookup | TRAFIKLAB_API_KEY | Sweden | | Trafiklab Timetables | TRAFIKLAB_API_KEY | Sweden | | GTFS-RT Service Alerts | TRAFIKLAB_GTFS_KEY | Sweden | | GTFS-RT Trip Updates | TRAFIKLAB_GTFS_KEY | Sweden | | GTFS-RT Vehicle Positions | TRAFIKLAB_GTFS_KEY | Sweden | | Combined Nearby Vehicles | TRAFIKLAB_GTFS_KEY | Stockholm |

Quick Start

To explore all endpoints interactively, open the built-in Swagger UI:

bun run --filter @transit-se/sdk inspect
import { TransitClient } from '@transit-se/sdk';

const client = new TransitClient({
  apiKey: process.env.TRAFIKLAB_API_KEY!,
});

// Search stops
const stops = await client.stops.searchByName('T-Centralen');

// Get departures
const departures = await client.timetables.getDepartures('740000001');

// SL-specific (no API key needed)
const slDepartures = await client.sl.getDepartures(9192);

// Check usage
console.log(client.getUsage());

API Reference

SL Transport

Stockholm-specific API. No API key required.

import { SLTransportApi } from '@transit-se/sdk/sl';

const sl = new SLTransportApi();

// Departures from Slussen (site ID 9192)
const deps = await sl.getDepartures(9192);
for (const dep of deps.departures) {
  console.log(`${dep.display} ${dep.line.designation} → ${dep.destination}`);
}

// Filter departures: only metro, direction 1, next 30 minutes
const filtered = await sl.getDepartures(9192, {
  transport: 'METRO',
  direction: 1,
  forecast: 30,
});

// All sites, lines (grouped by mode), stop points
const sites = await sl.getSites();
const lines = await sl.getLines();
const stopPoints = await sl.getStopPoints();

// Cached site lookups (fetched once, then instant)
const site = await sl.getSiteById(9192);
const slussen = await sl.getSiteByName('Slussen');
const matches = await sl.searchSitesByName('central');
const allCached = await sl.getCachedSites();

| Method | Endpoint | Description | | --------------------------------- | ------------------------------- | -------------------------------------------- | | getSites(expand?) | GET /v1/sites | List all sites (full response) | | getDepartures(siteId, options?) | GET /v1/sites/{id}/departures | Departures from a site (optionally filtered) | | getLines() | GET /v1/lines | Lines grouped by mode | | getStopPoints() | GET /v1/stop-points | List all stop points | | getTransportAuthorities() | GET /v1/transport-authorities | List transport authorities | | getCachedSites() | Cached | All sites (fetched once, then in-memory) | | getSiteById(id) | Cached | Look up a site by numeric ID | | getSiteByName(name) | Cached | Look up a site by exact name | | searchSitesByName(query) | Cached | Search sites by name substring |

Site ID note: IDs from Trafiklab Stop Lookup (format 300109001) need the prefix removed — 300109001 becomes 9001.

SL Deviations

Service disruptions, reroutes, and planned maintenance for Stockholm. No API key required.

import { SLDeviationsApi } from '@transit-se/sdk/sl';

const deviations = new SLDeviationsApi();

// All current deviations
const all = await deviations.getDeviations();

// Filter by transport mode and line
const metro = await deviations.getDeviations({
  transportModes: ['METRO'],
  lineIds: [13, 14],
});

for (const msg of metro) {
  const variant = msg.message_variants[0];
  console.log(`${variant.header}: ${variant.details}`);
}

| Method | Endpoint | Description | | ------------------------- | -------------------- | --------------------------------- | | getDeviations(options?) | GET /v1/deviations | Current and future service alerts |

Trafiklab Stop Lookup

Search and list public transport stops. Covers all of Sweden. Requires TRAFIKLAB_API_KEY.

import { TransitClient } from '@transit-se/sdk';

const client = new TransitClient({ apiKey: process.env.TRAFIKLAB_API_KEY! });

// Search stops by name
const result = await client.stops.searchByName('T-Centralen');
for (const group of result.stop_groups) {
  console.log(group.name, group.transport_modes);
}

// List all stops (sorted by daily departures)
const all = await client.stops.listAll();

| Method | Endpoint | Description | | --------------------- | ---------------------------- | -------------------- | | searchByName(query) | GET /v1/stops/name/{query} | Search stops by name | | listAll() | GET /v1/stops/list | List all stops |

Trafiklab Timetables

Departures and arrivals for the next 60 minutes from any stop. Requires TRAFIKLAB_API_KEY.

// Departures from T-Centralen
const deps = await client.timetables.getDepartures('740000001');
for (const dep of deps.departures) {
  console.log(`${dep.route.designation} → ${dep.route.direction} (delay: ${dep.delay}s)`);
}

// Arrivals at a specific time
const arrs = await client.timetables.getArrivals('740000001', '2025-04-01T16:00');

| Method | Endpoint | Description | | ------------------------------ | -------------------------------------- | ---------------------- | | getDepartures(areaId, time?) | GET /v1/departures/{areaId}[/{time}] | Departures from a stop | | getArrivals(areaId, time?) | GET /v1/arrivals/{areaId}[/{time}] | Arrivals at a stop |

GTFS-RT APIs

Real-time feeds covering all Swedish transit operators (Uppsala, Skane, Ostgotrafiken, and more). The SDK decodes protobuf into clean TypeScript objects. Requires TRAFIKLAB_GTFS_KEY.

For Stockholm (SL): Prefer the SL-specific APIs — they provide richer data and require no API key.

import {
  GtfsServiceAlertsApi,
  GtfsTripUpdatesApi,
  GtfsVehiclePositionsApi,
} from '@transit-se/sdk/gtfs';

const alerts = new GtfsServiceAlertsApi({ apiKey: process.env.TRAFIKLAB_GTFS_KEY! });
const trips = new GtfsTripUpdatesApi({ apiKey: process.env.TRAFIKLAB_GTFS_KEY! });
const vehicles = new GtfsVehiclePositionsApi({ apiKey: process.env.TRAFIKLAB_GTFS_KEY! });

// Service alerts for Uppsala
const ulAlerts = await alerts.getServiceAlerts('ul');

// Trip updates (delays, cancellations) for Skane
const skaneTrips = await trips.getTripUpdates('skane');

// Live vehicle positions for Uppsala
const ulVehicles = await vehicles.getVehiclePositions('ul');

| Method | Feed | Description | | ------------------------------- | --------------------------- | --------------------------------------------- | | getServiceAlerts(operator) | ServiceAlertsSweden.pb | Disruptions, reroutes, planned maintenance | | getTripUpdates(operator) | TripUpdatesSweden.pb | Per-trip delay predictions and cancellations | | getVehiclePositions(operator) | VehiclePositionsSweden.pb | Live GPS positions, speed, bearing, occupancy |

Supported operators: sl, ul, otraf, jlt, krono, klt, gotland, blekinge, skane, halland, varm, orebro, vastmanland, dt, xt, dintur.

Combined Nearby Vehicles

Find vehicles near a Stockholm location with automatic transport mode classification (metro, bus, tram, train, ferry, ship). Combines GTFS-RT vehicle positions with SL stop point data. Requires TRAFIKLAB_GTFS_KEY.

import { CombinedSLNearbyVehiclesApi } from '@transit-se/sdk/combined';
import { GtfsVehiclePositionsApi } from '@transit-se/sdk/gtfs';
import { SLTransportApi } from '@transit-se/sdk/sl';

const nearby = new CombinedSLNearbyVehiclesApi({
  vehiclePositionsApi: new GtfsVehiclePositionsApi({ apiKey: process.env.TRAFIKLAB_GTFS_KEY! }),
  slTransportApi: new SLTransportApi(),
});

// By station name
const result = await nearby.getNearbyVehicles({ siteName: 'Slussen' });

// By coordinates with custom radius
const result2 = await nearby.getNearbyVehicles({
  latitude: 59.3195,
  longitude: 18.0722,
  radiusKm: 2,
});

for (const v of result.vehicles) {
  console.log(`${v.transportMode} — ${v.distanceMeters}m away — ${v.vehicleLabel}`);
}

| Method | Description | | ---------------------------- | --------------------------------------------- | | getNearbyVehicles(options) | Vehicles near a site or coordinate with modes |

Standalone API Usage

Each API can be used independently without the TransitClient facade:

import { SLTransportApi, SLDeviationsApi } from '@transit-se/sdk/sl';
import { TrafiklabStopLookupApi, TrafiklabTimetablesApi } from '@transit-se/sdk/trafiklab';
import {
  GtfsServiceAlertsApi,
  GtfsTripUpdatesApi,
  GtfsVehiclePositionsApi,
} from '@transit-se/sdk/gtfs';

// SL APIs (no API key)
const sl = new SLTransportApi();
const deviations = new SLDeviationsApi();

// Trafiklab APIs (require TRAFIKLAB_API_KEY)
const stops = new TrafiklabStopLookupApi({ apiKey: 'your-key' });
const timetables = new TrafiklabTimetablesApi({ apiKey: 'your-key' });

// GTFS-RT APIs (require TRAFIKLAB_GTFS_KEY)
const alerts = new GtfsServiceAlertsApi({ apiKey: 'your-gtfs-key' });
const trips = new GtfsTripUpdatesApi({ apiKey: 'your-gtfs-key' });
const vehicles = new GtfsVehiclePositionsApi({ apiKey: 'your-gtfs-key' });

// Combined APIs (require TRAFIKLAB_GTFS_KEY)
import { CombinedSLNearbyVehiclesApi } from '@transit-se/sdk/combined';
const nearby = new CombinedSLNearbyVehiclesApi({
  vehiclePositionsApi: vehicles,
  slTransportApi: sl,
});

Response Validation

The SDK ships with optional Valibot schemas for JSON API responses (SL and Trafiklab APIs). GTFS-RT APIs use protobuf, which is self-validating.

import { TransitClient, ValidationError } from '@transit-se/sdk';

const client = new TransitClient({
  apiKey: process.env.TRAFIKLAB_API_KEY!,
  validate: true,
});

try {
  const stops = await client.stops.searchByName('T-Centralen');
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('API response changed:', error.message);
  }
}
  • validate: false (default) — zero overhead, zero deps. Responses are cast to TypeScript types.
  • validate: true — responses are parsed through Valibot schemas. Throws ValidationError on shape mismatch. Requires valibot as a peer dependency (bun add valibot).

Individual APIs also accept validate:

import { SLTransportApi } from '@transit-se/sdk/sl';

const sl = new SLTransportApi({ validate: true });

Schemas are exported for direct use:

import {
  TrafiklabStopLookupResponseSchema,
  SLDeparturesResponseSchema,
} from '@transit-se/sdk/schemas';

Usage Tracking

The SDK tracks API call counts so you can monitor your quota:

const client = new TransitClient({ apiKey: '...' });

await client.stops.searchByName('Slussen');
await client.timetables.getDepartures('740000001');

console.log(client.getUsage());
// { totalRequests: 2, byEndpoint: { '/name/Slussen': 1, '/departures/740000001': 1 } }

Individual API instances also expose getUsage().

Error Handling

import { ApiResponseError, ValidationError } from '@transit-se/sdk';

try {
  await client.timetables.getDepartures('invalid');
} catch (error) {
  if (error instanceof ApiResponseError) {
    console.error(`HTTP ${error.statusCode}: ${error.message}`);
  }
  if (error instanceof ValidationError) {
    console.error('API shape changed:', error.message);
  }
}