@atlasnpm/atlas-api-helper 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,22 +8,179 @@ npm install @atlasnpm/atlas-api-helper
8
8
 
9
9
  ## Usage
10
10
 
11
+ ### Using Typed Components (Recommended)
12
+
13
+ The client now supports typed component interfaces that provide IDE autocomplete and type checking:
14
+
11
15
  ```ts
12
- import { AtlasHttpClient } from "@atlasnpm/atlas-api-helper";
16
+ import { AtlasHttpClient, EntityComponents, TaskComponents } from "@atlasnpm/atlas-api-helper";
13
17
 
14
18
  const client = new AtlasHttpClient({
15
19
  baseUrl: "http://localhost:8000",
16
20
  token: "my-api-token",
17
21
  });
18
22
 
19
- // Basic entity operations
20
- const entities = await client.listEntities();
21
- console.log("Entities", entities);
23
+ // Create entity with typed components
24
+ const entityComponents: EntityComponents = {
25
+ telemetry: {
26
+ latitude: 40.7128,
27
+ longitude: -74.0060,
28
+ altitude_m: 120,
29
+ speed_m_s: 8.2,
30
+ heading_deg: 165,
31
+ },
32
+ health: {
33
+ battery_percent: 85,
34
+ },
35
+ communications: {
36
+ link_state: "connected",
37
+ },
38
+ task_catalog: {
39
+ supported_tasks: ["move_to_location", "survey_grid"],
40
+ },
41
+ };
42
+
43
+ await client.createEntity("drone-01", "asset", "Demo Drone", "drone", entityComponents);
44
+
45
+ // Create task with typed components
46
+ const taskComponents: TaskComponents = {
47
+ parameters: {
48
+ latitude: 40.123,
49
+ longitude: -74.456,
50
+ altitude_m: 120,
51
+ },
52
+ progress: {
53
+ percent: 0,
54
+ status_detail: "Pending",
55
+ },
56
+ };
57
+
58
+ await client.createTask("task-1", taskComponents, { entity_id: "drone-01" });
59
+ ```
60
+
61
+ ### Using Raw Objects (Legacy)
62
+
63
+ Raw component objects are still supported for backwards compatibility:
64
+
65
+ ```ts
66
+ import { AtlasHttpClient } from "@atlasnpm/atlas-api-helper";
67
+
68
+ const client = new AtlasHttpClient({
69
+ baseUrl: "http://localhost:8000",
70
+ token: "my-api-token",
71
+ });
22
72
 
73
+ // Basic entity operations with raw objects
23
74
  await client.createEntity("asset-1", "asset", "Surveyor One", "drone", {
24
75
  telemetry: { latitude: 40.7, longitude: -74.0 },
25
76
  });
26
77
  await client.createTask("survey-1", { parameters: { latitude: 40.7, longitude: -74.0 } });
78
+ ```
79
+
80
+ ## Typed Component Reference
81
+
82
+ ### Entity Components
83
+
84
+ The `EntityComponents` interface accepts the following typed component fields:
85
+
86
+ | Component | Type | Description |
87
+ |-----------|------|-------------|
88
+ | `telemetry` | `TelemetryComponent` | Position and motion data |
89
+ | `geometry` | `GeometryComponent` | GeoJSON geometry for geoentities |
90
+ | `task_catalog` | `TaskCatalogComponent` | Supported task identifiers |
91
+ | `media_refs` | `MediaRefItem[]` | References to media objects |
92
+ | `mil_view` | `MilViewComponent` | Military tactical classification |
93
+ | `health` | `HealthComponent` | Health and vital statistics |
94
+ | `sensor_refs` | `SensorRefItem[]` | Sensor configurations |
95
+ | `communications` | `CommunicationsComponent` | Network link status |
96
+ | `task_queue` | `TaskQueueComponent` | Current and queued work items |
97
+ | `custom_*` | `unknown` | Custom components (must be prefixed with `custom_`) |
98
+
99
+ #### TelemetryComponent
100
+
101
+ ```ts
102
+ const telemetry: TelemetryComponent = {
103
+ latitude: 40.7128, // degrees (WGS84)
104
+ longitude: -74.0060, // degrees (WGS84)
105
+ altitude_m: 120, // meters above sea level
106
+ speed_m_s: 8.2, // horizontal speed in m/s
107
+ heading_deg: 165, // heading (0=N, 90=E)
108
+ };
109
+ ```
110
+
111
+ #### GeometryComponent
112
+
113
+ ```ts
114
+ // Point
115
+ const point: GeometryComponent = { type: "Point", coordinates: [-74.0060, 40.7128] };
116
+
117
+ // LineString
118
+ const line: GeometryComponent = { type: "LineString", coordinates: [[-74.0060, 40.7128], [-74.0070, 40.7138]] };
119
+
120
+ // Polygon
121
+ const polygon: GeometryComponent = { type: "Polygon", coordinates: [[[-74.0060, 40.7128], [-74.0070, 40.7128], [-74.0060, 40.7128]]] };
122
+ ```
123
+
124
+ ### Task Components
125
+
126
+ The `TaskComponents` interface accepts:
127
+
128
+ | Component | Type | Description |
129
+ |-----------|------|-------------|
130
+ | `parameters` | `TaskParametersComponent` | Command parameters for task execution |
131
+ | `progress` | `TaskProgressComponent` | Runtime telemetry about execution |
132
+
133
+ ```ts
134
+ const taskComponents: TaskComponents = {
135
+ parameters: {
136
+ latitude: 40.123,
137
+ longitude: -74.456,
138
+ altitude_m: 120,
139
+ },
140
+ progress: {
141
+ percent: 65,
142
+ updated_at: "2025-11-25T08:45:00Z",
143
+ status_detail: "En route to destination",
144
+ },
145
+ };
146
+ ```
147
+
148
+ ### Custom Components
149
+
150
+ Custom components must be prefixed with `custom_`:
151
+
152
+ ```ts
153
+ const components: EntityComponents = {
154
+ telemetry: { latitude: 40.7128 },
155
+ custom_weather: { wind_speed: 12, gusts: 18 }, // Custom component
156
+ };
157
+ ```
158
+
159
+ ### Component Validation
160
+
161
+ The client validates component keys before transmission. Unknown component keys that don't start with `custom_` will throw an error:
162
+
163
+ ```ts
164
+ // This will throw an error
165
+ await client.createEntity("test", "asset", "Test", "drone", {
166
+ unknown_component: { foo: "bar" }, // Error: Unknown component 'unknown_component'
167
+ });
168
+
169
+ // This works
170
+ await client.createEntity("test", "asset", "Test", "drone", {
171
+ custom_mydata: { foo: "bar" }, // OK: prefixed with custom_
172
+ });
173
+ ```
174
+
175
+ ## Complete Example
176
+
177
+ ```ts
178
+ import { AtlasHttpClient } from "@atlasnpm/atlas-api-helper";
179
+
180
+ const client = new AtlasHttpClient({
181
+ baseUrl: "http://localhost:8000",
182
+ token: "my-api-token",
183
+ });
27
184
 
28
185
  // Entity telemetry updates
29
186
  const entity = await client.getEntityByAlias("drone-1");
package/dist/index.cjs CHANGED
@@ -20,10 +20,58 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- AtlasHttpClient: () => AtlasHttpClient
23
+ AtlasHttpClient: () => AtlasHttpClient,
24
+ componentsToRecord: () => componentsToRecord,
25
+ validateEntityComponents: () => validateEntityComponents
24
26
  });
25
27
  module.exports = __toCommonJS(index_exports);
26
28
 
29
+ // src/types/components.ts
30
+ var KNOWN_ENTITY_COMPONENTS = /* @__PURE__ */ new Set([
31
+ "telemetry",
32
+ "geometry",
33
+ "task_catalog",
34
+ "media_refs",
35
+ "mil_view",
36
+ "health",
37
+ "sensor_refs",
38
+ "communications",
39
+ "task_queue"
40
+ ]);
41
+ function validateEntityComponents(components) {
42
+ for (const key of Object.keys(components)) {
43
+ if (!KNOWN_ENTITY_COMPONENTS.has(key) && !key.startsWith("custom_")) {
44
+ throw new Error(
45
+ `Unknown component '${key}' in entity components. Custom components must be prefixed with 'custom_'`
46
+ );
47
+ }
48
+ }
49
+ }
50
+ function stripNulls(obj) {
51
+ const result = {};
52
+ for (const [key, value] of Object.entries(obj)) {
53
+ if (value === null || value === void 0) {
54
+ continue;
55
+ }
56
+ if (Array.isArray(value)) {
57
+ result[key] = value.map(
58
+ (item) => typeof item === "object" && item !== null ? stripNulls(item) : item
59
+ );
60
+ } else if (typeof value === "object") {
61
+ result[key] = stripNulls(value);
62
+ } else {
63
+ result[key] = value;
64
+ }
65
+ }
66
+ return result;
67
+ }
68
+ function componentsToRecord(components) {
69
+ if (components === void 0) {
70
+ return void 0;
71
+ }
72
+ return stripNulls(components);
73
+ }
74
+
27
75
  // src/httpClient.ts
28
76
  var AtlasHttpClient = class {
29
77
  baseUrl;
@@ -106,7 +154,10 @@ var AtlasHttpClient = class {
106
154
  alias,
107
155
  subtype
108
156
  };
109
- if (components !== void 0) payload.components = components;
157
+ if (components !== void 0) {
158
+ validateEntityComponents(components);
159
+ payload.components = componentsToRecord(components);
160
+ }
110
161
  return this.request("POST", "/entities", payload);
111
162
  }
112
163
  updateEntity(entityId, components, options) {
@@ -114,7 +165,10 @@ var AtlasHttpClient = class {
114
165
  throw new Error("AtlasHttpClient.updateEntity requires a components payload or subtype.");
115
166
  }
116
167
  const payload = {};
117
- if (components !== void 0) payload.components = components;
168
+ if (components !== void 0) {
169
+ validateEntityComponents(components);
170
+ payload.components = componentsToRecord(components);
171
+ }
118
172
  if (options?.subtype !== void 0) payload.subtype = options.subtype;
119
173
  return this.request("PATCH", `/entities/${entityId}`, payload);
120
174
  }
@@ -143,7 +197,7 @@ var AtlasHttpClient = class {
143
197
  status: options?.status || "pending"
144
198
  };
145
199
  if (options?.entity_id !== void 0) payload.entity_id = options.entity_id;
146
- if (components !== void 0) payload.components = components;
200
+ if (components !== void 0) payload.components = componentsToRecord(components);
147
201
  if (options?.extra !== void 0) payload.extra = options.extra;
148
202
  return this.request("POST", "/tasks", payload);
149
203
  }
@@ -154,7 +208,7 @@ var AtlasHttpClient = class {
154
208
  );
155
209
  }
156
210
  const payload = {};
157
- if (components !== void 0) payload.components = components;
211
+ if (components !== void 0) payload.components = componentsToRecord(components);
158
212
  if (options?.status !== void 0) payload.status = options.status;
159
213
  if (options?.entity_id !== void 0) payload.entity_id = options.entity_id;
160
214
  if (options?.extra !== void 0) payload.extra = options.extra;
@@ -267,5 +321,7 @@ var AtlasHttpClient = class {
267
321
  };
268
322
  // Annotate the CommonJS export names for ESM import in node:
269
323
  0 && (module.exports = {
270
- AtlasHttpClient
324
+ AtlasHttpClient,
325
+ componentsToRecord,
326
+ validateEntityComponents
271
327
  });
package/dist/index.d.cts CHANGED
@@ -1,3 +1,184 @@
1
+ /**
2
+ * Typed component interfaces for Atlas Command entities, tasks, and objects.
3
+ *
4
+ * These interfaces provide type safety and validation for component data
5
+ * before it is transmitted to the Atlas Command API.
6
+ */
7
+ /**
8
+ * Position and motion data for entities.
9
+ */
10
+ interface TelemetryComponent {
11
+ /** Latitude in degrees (WGS84) */
12
+ latitude?: number;
13
+ /** Longitude in degrees (WGS84) */
14
+ longitude?: number;
15
+ /** Altitude in meters above sea level */
16
+ altitude_m?: number;
17
+ /** Horizontal speed in meters/second */
18
+ speed_m_s?: number;
19
+ /** Heading in degrees (0=N, 90=E, etc.) */
20
+ heading_deg?: number;
21
+ }
22
+ /**
23
+ * GeoJSON geometry for geoentities.
24
+ */
25
+ interface GeometryComponent {
26
+ /** GeoJSON geometry type */
27
+ type: "Point" | "LineString" | "Polygon";
28
+ /** GeoJSON coordinates ([lon, lat] for Point) */
29
+ coordinates: number[] | number[][] | number[][][];
30
+ }
31
+ /**
32
+ * Lists supported task identifiers for an asset.
33
+ */
34
+ interface TaskCatalogComponent {
35
+ /** Task identifiers the asset can accept */
36
+ supported_tasks: string[];
37
+ }
38
+ /**
39
+ * A reference to a media object.
40
+ */
41
+ interface MediaRefItem {
42
+ /** Object ID in object storage */
43
+ object_id: string;
44
+ /** Role of the media reference */
45
+ role: "camera_feed" | "thumbnail";
46
+ }
47
+ /**
48
+ * Military tactical classification component.
49
+ */
50
+ interface MilViewComponent {
51
+ /** Tactical classification */
52
+ classification: "friendly" | "hostile" | "neutral" | "unknown" | "civilian";
53
+ /** ISO 8601 timestamp of last observation */
54
+ last_seen?: string;
55
+ }
56
+ /**
57
+ * Health and vital statistics for entities.
58
+ */
59
+ interface HealthComponent {
60
+ /** Battery percentage (0-100) */
61
+ battery_percent?: number;
62
+ }
63
+ /**
64
+ * A reference to a sensor with FOV/orientation metadata.
65
+ */
66
+ interface SensorRefItem {
67
+ /** Unique sensor identifier */
68
+ sensor_id: string;
69
+ /** Sensor type (e.g., 'radar') */
70
+ type: string;
71
+ /** Vertical field of view in degrees */
72
+ vertical_fov?: number;
73
+ /** Horizontal field of view in degrees */
74
+ horizontal_fov?: number;
75
+ /** Vertical orientation in degrees relative to level */
76
+ vertical_orientation?: number;
77
+ /** Horizontal orientation in degrees relative to front */
78
+ horizontal_orientation?: number;
79
+ }
80
+ /**
81
+ * Network link status component.
82
+ */
83
+ interface CommunicationsComponent {
84
+ /** Network link state */
85
+ link_state: "connected" | "disconnected" | "degraded" | "unknown";
86
+ }
87
+ /**
88
+ * Current and queued work items for an entity.
89
+ */
90
+ interface TaskQueueComponent {
91
+ /** Current task ID (null if idle) */
92
+ current_task_id: string | null;
93
+ /** Ordered list of queued task IDs */
94
+ queued_task_ids: string[];
95
+ }
96
+ /**
97
+ * All supported entity components with optional fields.
98
+ * Custom components (prefixed with custom_) are allowed via index signature.
99
+ */
100
+ interface EntityComponents {
101
+ telemetry?: TelemetryComponent;
102
+ geometry?: GeometryComponent;
103
+ task_catalog?: TaskCatalogComponent;
104
+ media_refs?: MediaRefItem[];
105
+ mil_view?: MilViewComponent;
106
+ health?: HealthComponent;
107
+ sensor_refs?: SensorRefItem[];
108
+ communications?: CommunicationsComponent;
109
+ task_queue?: TaskQueueComponent;
110
+ /** Custom components must be prefixed with custom_ */
111
+ [key: `custom_${string}`]: unknown;
112
+ }
113
+ /**
114
+ * Command parameters for task execution.
115
+ */
116
+ interface TaskParametersComponent {
117
+ latitude?: number;
118
+ longitude?: number;
119
+ altitude_m?: number;
120
+ /** Allow any additional parameters */
121
+ [key: string]: unknown;
122
+ }
123
+ /**
124
+ * Runtime telemetry about task execution.
125
+ */
126
+ interface TaskProgressComponent {
127
+ /** Progress percentage (0-100) */
128
+ percent?: number;
129
+ /** ISO 8601 timestamp of last update */
130
+ updated_at?: string;
131
+ /** Human-readable status detail */
132
+ status_detail?: string;
133
+ }
134
+ /**
135
+ * All supported task components.
136
+ */
137
+ interface TaskComponents {
138
+ parameters?: TaskParametersComponent;
139
+ progress?: TaskProgressComponent;
140
+ /** Allow any additional components */
141
+ [key: string]: unknown;
142
+ }
143
+ /**
144
+ * A reference from an object to an entity or task.
145
+ */
146
+ interface ObjectReferenceItem {
147
+ entity_id?: string;
148
+ task_id?: string;
149
+ }
150
+ /**
151
+ * Metadata for stored objects (JSON blob fields).
152
+ */
153
+ interface ObjectMetadata {
154
+ /** Storage bucket name */
155
+ bucket?: string;
156
+ /** File size in bytes */
157
+ size_bytes?: number;
158
+ /** Hints about object usage */
159
+ usage_hints?: string[];
160
+ /** Entities/tasks that reference this object */
161
+ referenced_by?: ObjectReferenceItem[];
162
+ /** Hash/checksum of object content */
163
+ checksum?: string;
164
+ /** ISO 8601 expiry timestamp */
165
+ expiry_time?: string;
166
+ /** Custom fields */
167
+ [key: `custom_${string}`]: unknown;
168
+ }
169
+ /**
170
+ * Validates that component keys are either known or prefixed with custom_.
171
+ */
172
+ declare function validateEntityComponents(components: Record<string, unknown>): void;
173
+ /**
174
+ * Convert typed components to a plain object for API transmission.
175
+ * Strips null and undefined values.
176
+ *
177
+ * @param components - Typed component object or raw record
178
+ * @returns Plain object suitable for JSON serialization
179
+ */
180
+ declare function componentsToRecord(components: EntityComponents | TaskComponents | Record<string, unknown> | undefined): Record<string, unknown> | undefined;
181
+
1
182
  interface FetchImplementation {
2
183
  (input: RequestInfo, init?: RequestInit): Promise<Response>;
3
184
  }
@@ -19,8 +200,8 @@ declare class AtlasHttpClient {
19
200
  listEntities(limit?: number, offset?: number): Promise<unknown>;
20
201
  getEntity(entityId: string): Promise<unknown>;
21
202
  getEntityByAlias(alias: string): Promise<unknown>;
22
- createEntity(entityId: string, entityType: string, alias: string, subtype: string, components?: JsonRecord): Promise<unknown>;
23
- updateEntity(entityId: string, components?: JsonRecord, options?: {
203
+ createEntity(entityId: string, entityType: string, alias: string, subtype: string, components?: EntityComponents | JsonRecord): Promise<unknown>;
204
+ updateEntity(entityId: string, components?: EntityComponents | JsonRecord, options?: {
24
205
  subtype?: string;
25
206
  }): Promise<unknown>;
26
207
  deleteEntity(entityId: string): Promise<unknown>;
@@ -33,12 +214,12 @@ declare class AtlasHttpClient {
33
214
  }): Promise<unknown>;
34
215
  listTasks(limit?: number, status?: string): Promise<unknown>;
35
216
  getTask(taskId: string): Promise<unknown>;
36
- createTask(taskId: string, components?: JsonRecord, options?: {
217
+ createTask(taskId: string, components?: TaskComponents | JsonRecord, options?: {
37
218
  status?: string;
38
219
  entity_id?: string;
39
220
  extra?: JsonRecord;
40
221
  }): Promise<unknown>;
41
- updateTask(taskId: string, components?: JsonRecord, options?: {
222
+ updateTask(taskId: string, components?: TaskComponents | JsonRecord, options?: {
42
223
  status?: string;
43
224
  entity_id?: string;
44
225
  extra?: JsonRecord;
@@ -217,4 +398,4 @@ interface FullDatasetOptions {
217
398
  object_limit?: number;
218
399
  }
219
400
 
220
- export { type Asset, AtlasHttpClient, type ChangedSinceOptions, type ClientOptions, type Command, type CommandDefinition, type Entity, type Event, type EventType, type FetchImplementation, type FullDatasetOptions, type GeoFeature, type JsonRecord, type Model, type ObjectCreate, type ObjectReference, type ObjectUpdate, type Sensor, type StoredObject, type Task, type TaskComplete, type TaskFail, type TaskStart, type TaskStatusUpdate, type Telemetry, type Track, type TrackTelemetry };
401
+ export { type Asset, AtlasHttpClient, type ChangedSinceOptions, type ClientOptions, type Command, type CommandDefinition, type CommunicationsComponent, type Entity, type EntityComponents, type Event, type EventType, type FetchImplementation, type FullDatasetOptions, type GeoFeature, type GeometryComponent, type HealthComponent, type JsonRecord, type MediaRefItem, type MilViewComponent, type Model, type ObjectCreate, type ObjectMetadata, type ObjectReference, type ObjectReferenceItem, type ObjectUpdate, type Sensor, type SensorRefItem, type StoredObject, type Task, type TaskCatalogComponent, type TaskComplete, type TaskComponents, type TaskFail, type TaskParametersComponent, type TaskProgressComponent, type TaskQueueComponent, type TaskStart, type TaskStatusUpdate, type Telemetry, type TelemetryComponent, type Track, type TrackTelemetry, componentsToRecord, validateEntityComponents };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,184 @@
1
+ /**
2
+ * Typed component interfaces for Atlas Command entities, tasks, and objects.
3
+ *
4
+ * These interfaces provide type safety and validation for component data
5
+ * before it is transmitted to the Atlas Command API.
6
+ */
7
+ /**
8
+ * Position and motion data for entities.
9
+ */
10
+ interface TelemetryComponent {
11
+ /** Latitude in degrees (WGS84) */
12
+ latitude?: number;
13
+ /** Longitude in degrees (WGS84) */
14
+ longitude?: number;
15
+ /** Altitude in meters above sea level */
16
+ altitude_m?: number;
17
+ /** Horizontal speed in meters/second */
18
+ speed_m_s?: number;
19
+ /** Heading in degrees (0=N, 90=E, etc.) */
20
+ heading_deg?: number;
21
+ }
22
+ /**
23
+ * GeoJSON geometry for geoentities.
24
+ */
25
+ interface GeometryComponent {
26
+ /** GeoJSON geometry type */
27
+ type: "Point" | "LineString" | "Polygon";
28
+ /** GeoJSON coordinates ([lon, lat] for Point) */
29
+ coordinates: number[] | number[][] | number[][][];
30
+ }
31
+ /**
32
+ * Lists supported task identifiers for an asset.
33
+ */
34
+ interface TaskCatalogComponent {
35
+ /** Task identifiers the asset can accept */
36
+ supported_tasks: string[];
37
+ }
38
+ /**
39
+ * A reference to a media object.
40
+ */
41
+ interface MediaRefItem {
42
+ /** Object ID in object storage */
43
+ object_id: string;
44
+ /** Role of the media reference */
45
+ role: "camera_feed" | "thumbnail";
46
+ }
47
+ /**
48
+ * Military tactical classification component.
49
+ */
50
+ interface MilViewComponent {
51
+ /** Tactical classification */
52
+ classification: "friendly" | "hostile" | "neutral" | "unknown" | "civilian";
53
+ /** ISO 8601 timestamp of last observation */
54
+ last_seen?: string;
55
+ }
56
+ /**
57
+ * Health and vital statistics for entities.
58
+ */
59
+ interface HealthComponent {
60
+ /** Battery percentage (0-100) */
61
+ battery_percent?: number;
62
+ }
63
+ /**
64
+ * A reference to a sensor with FOV/orientation metadata.
65
+ */
66
+ interface SensorRefItem {
67
+ /** Unique sensor identifier */
68
+ sensor_id: string;
69
+ /** Sensor type (e.g., 'radar') */
70
+ type: string;
71
+ /** Vertical field of view in degrees */
72
+ vertical_fov?: number;
73
+ /** Horizontal field of view in degrees */
74
+ horizontal_fov?: number;
75
+ /** Vertical orientation in degrees relative to level */
76
+ vertical_orientation?: number;
77
+ /** Horizontal orientation in degrees relative to front */
78
+ horizontal_orientation?: number;
79
+ }
80
+ /**
81
+ * Network link status component.
82
+ */
83
+ interface CommunicationsComponent {
84
+ /** Network link state */
85
+ link_state: "connected" | "disconnected" | "degraded" | "unknown";
86
+ }
87
+ /**
88
+ * Current and queued work items for an entity.
89
+ */
90
+ interface TaskQueueComponent {
91
+ /** Current task ID (null if idle) */
92
+ current_task_id: string | null;
93
+ /** Ordered list of queued task IDs */
94
+ queued_task_ids: string[];
95
+ }
96
+ /**
97
+ * All supported entity components with optional fields.
98
+ * Custom components (prefixed with custom_) are allowed via index signature.
99
+ */
100
+ interface EntityComponents {
101
+ telemetry?: TelemetryComponent;
102
+ geometry?: GeometryComponent;
103
+ task_catalog?: TaskCatalogComponent;
104
+ media_refs?: MediaRefItem[];
105
+ mil_view?: MilViewComponent;
106
+ health?: HealthComponent;
107
+ sensor_refs?: SensorRefItem[];
108
+ communications?: CommunicationsComponent;
109
+ task_queue?: TaskQueueComponent;
110
+ /** Custom components must be prefixed with custom_ */
111
+ [key: `custom_${string}`]: unknown;
112
+ }
113
+ /**
114
+ * Command parameters for task execution.
115
+ */
116
+ interface TaskParametersComponent {
117
+ latitude?: number;
118
+ longitude?: number;
119
+ altitude_m?: number;
120
+ /** Allow any additional parameters */
121
+ [key: string]: unknown;
122
+ }
123
+ /**
124
+ * Runtime telemetry about task execution.
125
+ */
126
+ interface TaskProgressComponent {
127
+ /** Progress percentage (0-100) */
128
+ percent?: number;
129
+ /** ISO 8601 timestamp of last update */
130
+ updated_at?: string;
131
+ /** Human-readable status detail */
132
+ status_detail?: string;
133
+ }
134
+ /**
135
+ * All supported task components.
136
+ */
137
+ interface TaskComponents {
138
+ parameters?: TaskParametersComponent;
139
+ progress?: TaskProgressComponent;
140
+ /** Allow any additional components */
141
+ [key: string]: unknown;
142
+ }
143
+ /**
144
+ * A reference from an object to an entity or task.
145
+ */
146
+ interface ObjectReferenceItem {
147
+ entity_id?: string;
148
+ task_id?: string;
149
+ }
150
+ /**
151
+ * Metadata for stored objects (JSON blob fields).
152
+ */
153
+ interface ObjectMetadata {
154
+ /** Storage bucket name */
155
+ bucket?: string;
156
+ /** File size in bytes */
157
+ size_bytes?: number;
158
+ /** Hints about object usage */
159
+ usage_hints?: string[];
160
+ /** Entities/tasks that reference this object */
161
+ referenced_by?: ObjectReferenceItem[];
162
+ /** Hash/checksum of object content */
163
+ checksum?: string;
164
+ /** ISO 8601 expiry timestamp */
165
+ expiry_time?: string;
166
+ /** Custom fields */
167
+ [key: `custom_${string}`]: unknown;
168
+ }
169
+ /**
170
+ * Validates that component keys are either known or prefixed with custom_.
171
+ */
172
+ declare function validateEntityComponents(components: Record<string, unknown>): void;
173
+ /**
174
+ * Convert typed components to a plain object for API transmission.
175
+ * Strips null and undefined values.
176
+ *
177
+ * @param components - Typed component object or raw record
178
+ * @returns Plain object suitable for JSON serialization
179
+ */
180
+ declare function componentsToRecord(components: EntityComponents | TaskComponents | Record<string, unknown> | undefined): Record<string, unknown> | undefined;
181
+
1
182
  interface FetchImplementation {
2
183
  (input: RequestInfo, init?: RequestInit): Promise<Response>;
3
184
  }
@@ -19,8 +200,8 @@ declare class AtlasHttpClient {
19
200
  listEntities(limit?: number, offset?: number): Promise<unknown>;
20
201
  getEntity(entityId: string): Promise<unknown>;
21
202
  getEntityByAlias(alias: string): Promise<unknown>;
22
- createEntity(entityId: string, entityType: string, alias: string, subtype: string, components?: JsonRecord): Promise<unknown>;
23
- updateEntity(entityId: string, components?: JsonRecord, options?: {
203
+ createEntity(entityId: string, entityType: string, alias: string, subtype: string, components?: EntityComponents | JsonRecord): Promise<unknown>;
204
+ updateEntity(entityId: string, components?: EntityComponents | JsonRecord, options?: {
24
205
  subtype?: string;
25
206
  }): Promise<unknown>;
26
207
  deleteEntity(entityId: string): Promise<unknown>;
@@ -33,12 +214,12 @@ declare class AtlasHttpClient {
33
214
  }): Promise<unknown>;
34
215
  listTasks(limit?: number, status?: string): Promise<unknown>;
35
216
  getTask(taskId: string): Promise<unknown>;
36
- createTask(taskId: string, components?: JsonRecord, options?: {
217
+ createTask(taskId: string, components?: TaskComponents | JsonRecord, options?: {
37
218
  status?: string;
38
219
  entity_id?: string;
39
220
  extra?: JsonRecord;
40
221
  }): Promise<unknown>;
41
- updateTask(taskId: string, components?: JsonRecord, options?: {
222
+ updateTask(taskId: string, components?: TaskComponents | JsonRecord, options?: {
42
223
  status?: string;
43
224
  entity_id?: string;
44
225
  extra?: JsonRecord;
@@ -217,4 +398,4 @@ interface FullDatasetOptions {
217
398
  object_limit?: number;
218
399
  }
219
400
 
220
- export { type Asset, AtlasHttpClient, type ChangedSinceOptions, type ClientOptions, type Command, type CommandDefinition, type Entity, type Event, type EventType, type FetchImplementation, type FullDatasetOptions, type GeoFeature, type JsonRecord, type Model, type ObjectCreate, type ObjectReference, type ObjectUpdate, type Sensor, type StoredObject, type Task, type TaskComplete, type TaskFail, type TaskStart, type TaskStatusUpdate, type Telemetry, type Track, type TrackTelemetry };
401
+ export { type Asset, AtlasHttpClient, type ChangedSinceOptions, type ClientOptions, type Command, type CommandDefinition, type CommunicationsComponent, type Entity, type EntityComponents, type Event, type EventType, type FetchImplementation, type FullDatasetOptions, type GeoFeature, type GeometryComponent, type HealthComponent, type JsonRecord, type MediaRefItem, type MilViewComponent, type Model, type ObjectCreate, type ObjectMetadata, type ObjectReference, type ObjectReferenceItem, type ObjectUpdate, type Sensor, type SensorRefItem, type StoredObject, type Task, type TaskCatalogComponent, type TaskComplete, type TaskComponents, type TaskFail, type TaskParametersComponent, type TaskProgressComponent, type TaskQueueComponent, type TaskStart, type TaskStatusUpdate, type Telemetry, type TelemetryComponent, type Track, type TrackTelemetry, componentsToRecord, validateEntityComponents };
package/dist/index.js CHANGED
@@ -1,3 +1,49 @@
1
+ // src/types/components.ts
2
+ var KNOWN_ENTITY_COMPONENTS = /* @__PURE__ */ new Set([
3
+ "telemetry",
4
+ "geometry",
5
+ "task_catalog",
6
+ "media_refs",
7
+ "mil_view",
8
+ "health",
9
+ "sensor_refs",
10
+ "communications",
11
+ "task_queue"
12
+ ]);
13
+ function validateEntityComponents(components) {
14
+ for (const key of Object.keys(components)) {
15
+ if (!KNOWN_ENTITY_COMPONENTS.has(key) && !key.startsWith("custom_")) {
16
+ throw new Error(
17
+ `Unknown component '${key}' in entity components. Custom components must be prefixed with 'custom_'`
18
+ );
19
+ }
20
+ }
21
+ }
22
+ function stripNulls(obj) {
23
+ const result = {};
24
+ for (const [key, value] of Object.entries(obj)) {
25
+ if (value === null || value === void 0) {
26
+ continue;
27
+ }
28
+ if (Array.isArray(value)) {
29
+ result[key] = value.map(
30
+ (item) => typeof item === "object" && item !== null ? stripNulls(item) : item
31
+ );
32
+ } else if (typeof value === "object") {
33
+ result[key] = stripNulls(value);
34
+ } else {
35
+ result[key] = value;
36
+ }
37
+ }
38
+ return result;
39
+ }
40
+ function componentsToRecord(components) {
41
+ if (components === void 0) {
42
+ return void 0;
43
+ }
44
+ return stripNulls(components);
45
+ }
46
+
1
47
  // src/httpClient.ts
2
48
  var AtlasHttpClient = class {
3
49
  baseUrl;
@@ -80,7 +126,10 @@ var AtlasHttpClient = class {
80
126
  alias,
81
127
  subtype
82
128
  };
83
- if (components !== void 0) payload.components = components;
129
+ if (components !== void 0) {
130
+ validateEntityComponents(components);
131
+ payload.components = componentsToRecord(components);
132
+ }
84
133
  return this.request("POST", "/entities", payload);
85
134
  }
86
135
  updateEntity(entityId, components, options) {
@@ -88,7 +137,10 @@ var AtlasHttpClient = class {
88
137
  throw new Error("AtlasHttpClient.updateEntity requires a components payload or subtype.");
89
138
  }
90
139
  const payload = {};
91
- if (components !== void 0) payload.components = components;
140
+ if (components !== void 0) {
141
+ validateEntityComponents(components);
142
+ payload.components = componentsToRecord(components);
143
+ }
92
144
  if (options?.subtype !== void 0) payload.subtype = options.subtype;
93
145
  return this.request("PATCH", `/entities/${entityId}`, payload);
94
146
  }
@@ -117,7 +169,7 @@ var AtlasHttpClient = class {
117
169
  status: options?.status || "pending"
118
170
  };
119
171
  if (options?.entity_id !== void 0) payload.entity_id = options.entity_id;
120
- if (components !== void 0) payload.components = components;
172
+ if (components !== void 0) payload.components = componentsToRecord(components);
121
173
  if (options?.extra !== void 0) payload.extra = options.extra;
122
174
  return this.request("POST", "/tasks", payload);
123
175
  }
@@ -128,7 +180,7 @@ var AtlasHttpClient = class {
128
180
  );
129
181
  }
130
182
  const payload = {};
131
- if (components !== void 0) payload.components = components;
183
+ if (components !== void 0) payload.components = componentsToRecord(components);
132
184
  if (options?.status !== void 0) payload.status = options.status;
133
185
  if (options?.entity_id !== void 0) payload.entity_id = options.entity_id;
134
186
  if (options?.extra !== void 0) payload.extra = options.extra;
@@ -240,5 +292,7 @@ var AtlasHttpClient = class {
240
292
  }
241
293
  };
242
294
  export {
243
- AtlasHttpClient
295
+ AtlasHttpClient,
296
+ componentsToRecord,
297
+ validateEntityComponents
244
298
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlasnpm/atlas-api-helper",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "description": "HTTP client for the Atlas Command REST API.",
6
6
  "license": "MIT",