Skip to content

Quickstart — TypeScript SDK

The same "list telescopes, create an observation, watch it run" walkthrough as the curl quickstart, using the TypeScript SDK. For the full treatment (catalog/non-sidereal targets, exposure sizing, asset download) see Creating observations.

Prereqs

  • Node 20+ and npm install skynet-sdk.
  • An access token. See Auth.

Setup

import {
  Client,
  MeApi,
  ObservingAccessApi,
  ObservingGrantsApi,
  TelescopesApi,
  ObservationsApi,
} from 'skynet-sdk';

const client = new Client({
  baseUrl: 'https://api.skynetgo.org/v1',
  token: process.env.SKYNET_TOKEN!, // bearer token
});

const me = new MeApi(client);
const access = new ObservingAccessApi(client);
const grants = new ObservingGrantsApi(client);
const telescopes = new TelescopesApi(client);
const observations = new ObservationsApi(client);

If you need refresh-token rotation, wrap token in an async provider when constructing Client — the SDK calls the provider on every request so a single refresh refreshes future calls too.

Walkthrough

An observation is created in one call from a complete spec — there's no draft-then-publish handshake. The wire format is camelCase, and the TS types match.

async function main() {
  // 1. Who am I? (slug is the entity in the create path)
  const user = await me.get();
  console.log(`Hello, ${user.username}`);

  // 2. A telescope you can submit to
  const scopes = await access.telescopes();
  const telescopeId = scopes[0].id;

  // 3. A grant that funds it + the imager and a filter
  const grantPage = await grants.list({ telescopeId });
  const grantId = grantPage.items[0].id;

  const detail = await telescopes.detailForEntity(user.slug, telescopeId);
  const imager = detail.instruments.find(i => i.instrumentType === 'opticalImager')!;
  const filterId = imager.filterWheels[0].options[0].filters[0].id;

  // 4. Create the observation in one call. Method names follow the generated
  //    openapi-typescript bindings; the body is camelCase.
  const created = await observations.create(user.slug, {
    name: 'TS Quickstart M51',
    target: {
      name: 'M51',
      position: {
        positionType: 'fixed',
        coordinates: { coordinateType: 'equatorial', raDeg: 202.4696, decDeg: 47.1952 },
      },
    },
    opticalImagingConfiguration: {
      trackingMode: 'sidereal',
      ditherStrategy: 'none',
      temporalOffsetSec: 0.0,
      maxTiles: 1,
      tileOverlap: 0.0,
    },
    requests: [{
      requestType: 'opticalImaging',
      order: 0,
      filterSpecifierIds: [filterId],
      exposureTimeSec: 60.0,
      sampleCount: 1,
    }],
    observingGrantIds: [grantId],   // pins the telescope
    instrumentIds: [imager.id],
  });
  console.log(`Created observation ${created.id} (status=${created.status})`);

  // 5. Watch it run
  for (let i = 0; i < 5; i++) {
    await new Promise(r => setTimeout(r, 20_000));
    const obs = await observations.get(created.id);
    console.log(`${i}: status=${obs.status} progress=${obs.progressFraction}`);
  }
}

main().catch(err => {
  console.error('Failed:', err);
  process.exit(1);
});

Notes

  • Method names above are illustrative — the exact names depend on the generated openapi-typescript bindings. Look at packages/ts/skynet-sdk/src/apis/ for the canonical method set per resource.
  • Wire format is camelCaserequestType: 'opticalImaging', not request_type: 'optical_imaging'. See Conventions.
  • Set exactly one exposure-sizing field per request (exposureTimeSec, targetSnr, or targetFullWellFraction).
  • Polymorphic resources use discriminators (requestType, positionType, etc.); the TS types are discriminated unions so TypeScript narrows the concrete shape automatically when you switch on the discriminator.

Errors

The SDK rejects non-2xx responses. Catch the rejection and switch on the status:

try {
  await observations.create(user.slug, body);
} catch (err) {
  if (err.status === 422) {
    console.log('Validation failed:', err.body.detail);
  } else if (err.status === 403) {
    console.log('Token missing the right scope');
  } else {
    throw err;
  }
}

Next steps