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 camelCase —
requestType: 'opticalImaging', notrequest_type: 'optical_imaging'. See Conventions. - Set exactly one exposure-sizing field per request
(
exposureTimeSec,targetSnr, ortargetFullWellFraction). - 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¶
- Creating observations — catalog and non-sidereal targets, exposure sizing, asset download.
- For realtime subscriptions, see WebSocket streams.
- For the Python equivalent, see quickstart — Python SDK.