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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@atlasnpm/atlas-api-helper

v0.2.10

Published

HTTP client for the Atlas Command REST API.

Readme

Atlas Command HTTP Client (TypeScript)

A TypeScript client for the Atlas Command REST API with full type support for entities, tasks, objects, and queries.

Installation

npm install @atlasnpm/atlas-api-helper

Requirements: Node.js 18+

Quick Start

import { AtlasHttpClient } from "@atlasnpm/atlas-api-helper";

const client = new AtlasHttpClient({
  baseUrl: "http://localhost:8000",
  token: "my-api-token",  // Optional Bearer token
});

// Create an entity
await client.createEntity("drone-01", "asset", "Demo Drone", "drone", {
  telemetry: { latitude: 40.7128, longitude: -74.0060 },
});

// Create a task assigned to the entity
await client.createTask("task-1", { parameters: { altitude_m: 120 } }, {
  entity_id: "drone-01",
});

// Start and complete the task
await client.startTask("task-1");
await client.completeTask("task-1");

Client Configuration

interface ClientOptions {
  baseUrl: string;              // Atlas Command server URL
  token?: string;               // Optional Bearer token for Authorization header
  fetchImpl?: FetchImplementation;  // Custom fetch function (defaults to globalThis.fetch)
}

Entity Operations

Creating Entities

createEntity(
  entityId: string,
  entityType: string,  // "asset" | "track" | "geofeature"
  alias: string,
  subtype: string,
  components?: EntityComponents | JsonRecord
): Promise<Entity>

Example:

await client.createEntity("drone-01", "asset", "Demo Drone", "drone", {
  telemetry: {
    latitude: 40.7128,
    longitude: -74.0060,
    altitude_m: 120,
    speed_m_s: 8.2,
    heading_deg: 165,
  },
  health: { battery_percent: 85 },
  communications: { link_state: "connected" },
});

Updating Entities

updateEntity(
  entityId: string,
  components?: EntityComponents | JsonRecord,
  options?: { subtype?: string }
): Promise<Entity>

At least one of components or options.subtype must be provided.

Example:

// Update components only
await client.updateEntity("drone-01", { health: { battery_percent: 72 } });

// Update subtype only
await client.updateEntity("drone-01", undefined, { subtype: "quadcopter" });

// Update both
await client.updateEntity("drone-01", { health: { battery_percent: 72 } }, { subtype: "quadcopter" });

Updating Telemetry

A convenience method for updating only telemetry fields:

updateEntityTelemetry(
  entityId: string,
  options: {
    latitude?: number;
    longitude?: number;
    altitude_m?: number;
    speed_m_s?: number;
    heading_deg?: number;
  }
): Promise<Entity>

Example:

await client.updateEntityTelemetry("drone-01", {
  latitude: 40.7128,
  longitude: -74.0060,
  altitude_m: 100,
  speed_m_s: 15,
  heading_deg: 90,
});

Other Entity Methods

| Method | Description | |--------|-------------| | listEntities(limit?, offset?) | List entities with pagination (defaults: limit=100, offset=0) | | getEntity(entityId) | Get entity by ID | | getEntityByAlias(alias) | Get entity by alias | | deleteEntity(entityId) | Delete an entity |

Task Operations

Creating Tasks

createTask(
  taskId: string,
  components?: TaskComponents | JsonRecord,
  options?: {
    status?: string;      // Defaults to "pending"
    entity_id?: string;   // Entity to assign the task to
    extra?: JsonRecord;   // Additional metadata
  }
): Promise<Task>

Example:

await client.createTask("mission-1", {
  parameters: { latitude: 40.123, longitude: -74.456, altitude_m: 120 },
  progress: { percent: 0, status_detail: "Pending" },
}, {
  entity_id: "drone-01",
  status: "pending",
});

Updating Tasks

updateTask(
  taskId: string,
  components?: TaskComponents | JsonRecord,
  options?: {
    status?: string;
    entity_id?: string;
    extra?: JsonRecord;
  }
): Promise<Task>

At least one of components or options must be provided.

Example:

await client.updateTask("mission-1", {
  progress: { percent: 50, status_detail: "En route" },
});

Task Lifecycle Methods

startTask(taskId: string): Promise<Task>
completeTask(taskId: string): Promise<Task>
failTask(taskId: string, errorMessage?: string, errorDetails?: JsonRecord): Promise<Task>

Example:

await client.startTask("mission-1");
// ... task execution ...
await client.completeTask("mission-1");

// Or if the task fails:
await client.failTask("mission-2", "Calibration failed", { code: "CAL-01" });

Other Task Methods

| Method | Description | |--------|-------------| | listTasks(limit?, status?) | List tasks with optional status filter (default limit: 25) | | getTask(taskId) | Get task by ID | | deleteTask(taskId) | Delete a task | | getTasksByEntity(entityId, limit?, status?) | Get tasks for an entity |

Object Operations

Uploading Objects

createObject(
  file: Blob | File,
  objectId: string,
  usageHint?: string,
  referencedBy?: Array<{ entity_id?: string; task_id?: string }>
): Promise<StoredObject>

Example:

const videoBlob = new Blob([videoData], { type: "video/mp4" });
const stored = await client.createObject(videoBlob, "mission-video", "mission_recording", [
  { entity_id: "drone-01" },
  { task_id: "mission-1" },
]);

Updating Object Metadata

updateObject(
  objectId: string,
  usageHints?: string[],
  referencedBy?: Array<{ entity_id?: string; task_id?: string }>
): Promise<StoredObject>

At least one of usageHints or referencedBy must be provided.

Example:

await client.updateObject("mission-video", ["final_recording", "approved"], [
  { task_id: "mission-1" },
]);

Object Reference Methods

| Method | Description | |--------|-------------| | addObjectReference(objectId, entityId?, taskId?) | Add reference to entity/task | | removeObjectReference(objectId, entityId?, taskId?) | Remove reference | | getObjectReferences(objectId) | Get all references for an object | | validateObjectReferences(objectId) | Check if references point to existing entities/tasks | | cleanupObjectReferences(objectId) | Remove references to deleted entities/tasks |

Other Object Methods

| Method | Description | |--------|-------------| | listObjects(limit?, offset?, contentType?, type?) | List objects with filters | | getObject(objectId) | Get object by ID | | deleteObject(objectId) | Delete an object | | getObjectsByEntity(entityId, limit?) | Get objects referenced by an entity | | getObjectsByTask(taskId, limit?) | Get objects referenced by a task | | findOrphanedObjects(limit?) | Find objects with no references |

Query Operations

Changed Since

Get entities, tasks, and objects modified after a timestamp:

getChangedSince(since: string, limitPerType?: number): Promise<ChangedSinceResponse>

Example:

const changes = await client.getChangedSince("2025-01-01T00:00:00Z", 50);

Full Dataset

Get a snapshot of all data with configurable limits:

getFullDataset(options?: {
  entityLimit?: number;
  taskLimit?: number;
  objectLimit?: number;
}): Promise<FullDatasetResponse>

Example:

const snapshot = await client.getFullDataset({
  entityLimit: 100,
  taskLimit: 50,
  objectLimit: 200,
});

Typed Components

The client provides type-safe interfaces for entity and task components. Use these to get IDE autocomplete and compile-time validation.

Entity Components

import type { EntityComponents, TelemetryComponent } from "@atlasnpm/atlas-api-helper";

const components: EntityComponents = {
  telemetry: {
    latitude: 40.7128,      // degrees (WGS84)
    longitude: -74.0060,    // degrees (WGS84)
    altitude_m: 120,        // meters above sea level
    speed_m_s: 8.2,         // horizontal speed in m/s
    heading_deg: 165,       // heading (0=N, 90=E)
  },
  geometry: {
    type: "Point",          // "Point" | "LineString" | "Polygon"
    coordinates: [-74.0060, 40.7128],
  },
  health: {
    battery_percent: 85,
  },
  communications: {
    link_state: "connected",  // "connected" | "disconnected" | "degraded" | "unknown"
  },
  task_catalog: {
    supported_tasks: ["move_to_location", "survey_grid"],
  },
  task_queue: {
    current_task_id: "mission-1",
    queued_task_ids: ["mission-2", "mission-3"],
  },
  mil_view: {
    classification: "friendly",  // "friendly" | "hostile" | "neutral" | "unknown" | "civilian"
    last_seen: "2025-12-01T10:30:00Z",
  },
  media_refs: [
    { object_id: "video-001", role: "camera_feed" },
  ],
  sensor_refs: [
    { sensor_id: "radar-1", type: "radar", horizontal_fov: 120 },
  ],
};

Task Components

import type { TaskComponents } from "@atlasnpm/atlas-api-helper";

const taskComponents: TaskComponents = {
  parameters: {
    latitude: 40.123,
    longitude: -74.456,
    altitude_m: 120,
    // Additional custom parameters are allowed
    speed_limit: 25,
  },
  progress: {
    percent: 65,
    updated_at: "2025-12-01T08:45:00Z",
    status_detail: "En route to destination",
  },
};

Custom Components

Custom components must be prefixed with custom_:

const components: EntityComponents = {
  telemetry: { latitude: 40.7128 },
  custom_weather: { wind_speed: 12, gusts: 18 },
  custom_mission_data: { priority: "high" },
};

Component Validation

The client validates entity component keys before sending requests. Unknown keys that don't start with custom_ will throw an error:

// This will throw: "Unknown component 'unknown_key'..."
await client.createEntity("test", "asset", "Test", "drone", {
  unknown_key: { foo: "bar" },
});

// This works - prefixed with custom_
await client.createEntity("test", "asset", "Test", "drone", {
  custom_mydata: { foo: "bar" },
});

Error Handling

All methods throw an Error on non-2xx responses. The error message includes the HTTP status and response body:

try {
  await client.getEntity("nonexistent");
} catch (error) {
  // Error: HTTP 404: {"detail":"Entity not found","code":"ENTITY_NOT_FOUND"}
  console.error(error.message);
}

For 204 No Content responses (like successful deletes), methods return undefined.

TypeScript Types

The package exports comprehensive types for all API resources:

import type {
  // Core types
  Entity,
  Task,
  StoredObject,
  
  // Entity aliases
  Asset,
  Track,
  GeoFeature,
  Command,
  
  // Component types
  EntityComponents,
  TaskComponents,
  TelemetryComponent,
  GeometryComponent,
  HealthComponent,
  CommunicationsComponent,
  TaskCatalogComponent,
  TaskQueueComponent,
  MilViewComponent,
  MediaRefItem,
  SensorRefItem,
  TaskParametersComponent,
  TaskProgressComponent,
  
  // Object types
  ObjectMetadata,
  ObjectReferenceItem,
  ObjectReference,
  ObjectCreate,
  ObjectUpdate,
  
  // Task lifecycle
  TaskStatusUpdate,
  TaskStart,
  TaskComplete,
  TaskFail,
  Telemetry,
  
  // Other entity types
  Model,
  CommandDefinition,
  EventType,
  Event,
  Sensor,
  TrackTelemetry,
  
  // Query types
  ChangedSinceOptions,
  FullDatasetOptions,
  
  // Client types
  ClientOptions,
  FetchImplementation,
  JsonRecord,
} from "@atlasnpm/atlas-api-helper";

Utility Functions

import { validateEntityComponents, componentsToRecord } from "@atlasnpm/atlas-api-helper";

// Validate component keys (throws on unknown non-custom keys)
validateEntityComponents({ telemetry: {}, custom_data: {} });

// Convert components to plain object, stripping null/undefined values
const cleaned = componentsToRecord({ telemetry: { latitude: 40.7, altitude_m: undefined } });
// Result: { telemetry: { latitude: 40.7 } }

Custom Fetch / Testing

Pass a custom fetchImpl when constructing the client to inject your own transport (e.g., node-fetch, cross-fetch, or a mocked implementation for unit tests):

const client = new AtlasHttpClient({
  baseUrl: "https://atlas.example.com",
  fetchImpl: myCustomFetch,
});

See tests/httpClient.test.ts for examples using mocked fetch functions.

Building & Testing

npm install
npm run build
npm run test

The build produces both ESM and CJS bundles plus .d.ts type definitions via tsup.

Publishing

Publishing is handled by .github/workflows/publish-atlas-api-helper-npm.yml. Ensure the @atlasnpm scope and automation token are set up as documented in the workflow README before triggering a release.