@dronedeploy/rocos-js-sdk 3.1.5 → 3.1.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.
Files changed (35) hide show
  1. package/cjs/constants/api.d.ts +1 -0
  2. package/cjs/constants/api.js +3 -2
  3. package/cjs/helpers/getRobotStatusColour.d.ts +25 -0
  4. package/cjs/helpers/getRobotStatusColour.js +54 -0
  5. package/cjs/helpers/index.d.ts +1 -0
  6. package/cjs/helpers/index.js +1 -0
  7. package/cjs/models/index.d.ts +2 -0
  8. package/cjs/models/index.js +2 -0
  9. package/cjs/models/maps/Panorama.d.ts +18 -0
  10. package/cjs/models/robot-status/RobotStatus.d.ts +43 -0
  11. package/cjs/models/robot-status/RobotStatus.js +2 -0
  12. package/cjs/models/robot-status/RobotStatusEnums.d.ts +54 -0
  13. package/cjs/models/robot-status/RobotStatusEnums.js +61 -0
  14. package/cjs/services/CallerService.d.ts +38 -0
  15. package/cjs/services/CallerService.js +56 -0
  16. package/cjs/services/MapService.d.ts +20 -1
  17. package/cjs/services/MapService.js +21 -0
  18. package/esm/constants/api.d.ts +1 -0
  19. package/esm/constants/api.js +1 -0
  20. package/esm/helpers/getRobotStatusColour.d.ts +25 -0
  21. package/esm/helpers/getRobotStatusColour.js +50 -0
  22. package/esm/helpers/index.d.ts +1 -0
  23. package/esm/helpers/index.js +1 -0
  24. package/esm/models/index.d.ts +2 -0
  25. package/esm/models/index.js +2 -0
  26. package/esm/models/maps/Panorama.d.ts +18 -0
  27. package/esm/models/robot-status/RobotStatus.d.ts +43 -0
  28. package/esm/models/robot-status/RobotStatus.js +1 -0
  29. package/esm/models/robot-status/RobotStatusEnums.d.ts +54 -0
  30. package/esm/models/robot-status/RobotStatusEnums.js +58 -0
  31. package/esm/services/CallerService.d.ts +38 -0
  32. package/esm/services/CallerService.js +57 -1
  33. package/esm/services/MapService.d.ts +20 -1
  34. package/esm/services/MapService.js +22 -1
  35. package/package.json +1 -1
@@ -131,6 +131,7 @@ export declare const API_GRAPHS_MAP_METADATA_URL = "https://{url}/graphs/project
131
131
  export declare const API_GRAPHS_MAPS_COPY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy";
132
132
  export declare const API_GRAPHS_MAPS_DEPLOY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy";
133
133
  export declare const API_GRAPHS_MAPS_GEOJSON_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson";
134
+ export declare const API_GRAPHS_PANORAMAS_URL = "https://{url}/graphs/projects/{projectId}/panoramas";
134
135
  export declare const API_GRAPHS_PANORAMA = "https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}";
135
136
  export declare const API_GRAPHS_PANORAMA_OBSERVATIONS_URL = "https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}/observations";
136
137
  export declare const API_GRAPHS_OBSERVATIONS_URL = "https://{url}/graphs/projects/{projectId}/observations";
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.API_PROJECT_ROBOT_EVENT_URL = exports.API_PROJECT_ROBOT_REGISTER_URL = exports.API_PROJECT_ROBOT_DEFINITION_URL = exports.API_PROJECT_ROBOT_ATTRIBUTES_URL = exports.API_PROJECT_ROBOT_ID_URL = exports.API_ACCOUNT_ROBOT_URL = exports.API_PROJECT_ROBOT_URL = exports.API_PROJECT_MAPPED_ASSET_PATH_URL = exports.API_PROJECT_MAPPED_ASSETS_PATH_URL = exports.API_PROJECT_MISSION_ASSET_PATH_URL = exports.API_PROJECT_MISSION_ASSETS_PATH_URL = exports.API_PROJECT_FLOW_ASSET_PATH_URL = exports.API_PROJECT_ROBOT_ASSET_PATH_URL = exports.API_PROJECT_ASSET_INTEGRATION_PATH_URL = exports.API_PROJECT_ASSET_INTEGRATIONS_PATH_URL = exports.API_PROJECT_ASSET_INTEGRATION_PROVIDERS_PATH_URL = exports.API_PROJECT_ASSET_PROFILES_SYNC_DEFINITION_PATH_URL = exports.API_PROJECT_ASSET_ROBOTS_SYNC_DEFINITION_PATH_URL = exports.API_PROJECT_ASSET_PATH_URL = exports.API_PROJECT_ASSET_URL = exports.API_PROJECT_USERS_URL = exports.API_PROJECT_ID_URL = exports.API_PROJECT_URL = exports.API_ACCOUNT_EXTERNAL_PROJECTS_URL = exports.API_ACCOUNT_PROJECT_APPLICATION_ID_URL = exports.API_ACCOUNT_PROJECT_APPLICATION_URL = exports.API_ACCOUNT_PROJECT_USER_ID_URL = exports.API_ACCOUNT_PROJECT_USER_URL = exports.API_ACCOUNT_PROJECT_ID_URL = exports.API_ACCOUNT_PROJECT_URL = exports.API_SERVER_TIME_URL = exports.API_ACCOUNT_SETTINGS_URL = exports.API_AUTH_USER_ACCOUNT_USER_ID_URL = exports.API_AUTH_USER_ACCOUNT_USER_URL = exports.API_ACCOUNT_ACTIVATE_URL = exports.API_ACCOUNT_ID_URL = exports.API_ACCOUNT_URL = exports.API_USER_PAT_TOKEN_URL = exports.API_USER_PAT_URL = exports.API_USER_VERIFY_EMAIL_URL = exports.API_USER_INVITATION_CHECK_URL = exports.API_USER_INVITATION_ACCEPT_URL = exports.API_USER_INVITATION_URL = exports.API_USER_PASSWORD_FORGOT_URL = exports.API_OTP_AUTH_URL = exports.API_OTP_URL = exports.API_USER_TOKEN_URL = exports.API_USER_URL = exports.API_ADMIN_USER_INVITATION_URL = exports.API_APPLICATION_AUTH_URL = void 0;
4
4
  exports.API_PROJECT_STREAM_DATA_URL = exports.API_PROJECT_STREAM_ID_URL = exports.API_PROJECT_STREAM_URL = exports.API_PROJECT_GROUP_TYPE_OWNER_OVERRIDE_URL = exports.API_PROJECT_GROUP_TYPE_OWNER_ID_URL = exports.API_PROJECT_GROUP_TYPE_VERSION_URL = exports.API_PROJECT_GROUP_TYPE_CONFIG_URL = exports.API_PROJECT_GROUP_TYPE_PUBLISH_URL = exports.API_PROJECT_GROUP_TYPE_ID_URL = exports.API_PROJECT_GROUP_TYPE_URL = exports.API_PROJECT_ENVIRONMENT_URL = exports.API_PROJECT_DEFINITION_LIBRARY = exports.API_PROJECT_DEFINITION_IMPORT_LIBRARY = exports.API_PROJECT_DEFINITION_IMPORT = exports.API_PROJECT_DEFINITION_EXPORT = exports.API_PROJECT_DEFINITION_GAMEPAD_URL = exports.API_PROJECT_DEFINITION_TRIGGER_URL = exports.API_PROJECT_DEFINITION_BUTTON_URL = exports.API_PROJECT_DEFINITION_ACTION_URL = exports.API_PROJECT_DEFINITION_EVENT_URL = exports.API_PROJECT_DEFINITION_COMMAND2_URL = exports.API_PROJECT_DEFINITION_COMMAND_URL = exports.API_PROJECT_DEFINITION_AGENT_URL = exports.API_PROJECT_DEFINITION_SETTING_URL = exports.API_PROJECT_DEFINITION_BLOB_URL = exports.API_PROJECT_DEFINITION_DASHBOARD_URL = exports.API_PROJECT_DEFINITION_COPY_URL = exports.API_PROJECT_DEFINITION_STREAM_URL = exports.API_PROJECT_DEFINITION_ID_URL = exports.API_PROJECT_DEFINITION_URL = exports.API_PROJECT_VROBOT_DEPLOY_URL = exports.API_PROJECT_VROBOT_DETAILS_URL = exports.API_PROJECT_COLLECTION_DOCS_URL = exports.API_PROJECT_COLLECTION_ID_URL = exports.API_PROJECT_DASHBOARD_CUSTOM_WIDGET_URL = exports.API_PROJECT_DASHBOARD_WIDGET_URL = exports.API_PROJECT_DASHBOARD_ID_URL = exports.API_PROJECT_DASHBOARD_URL = exports.API_PROJECT_OPERATION_ID_URL = exports.API_PROJECT_OPERATION_URL = exports.API_PROJECT_ROBOT_CONFIGS_CONNECTION_URL = exports.API_PROJECT_ROBOT_CONFIGS_CONNECTIONS_URL = exports.API_PROJECT_ROBOT_GAMEPAD_URL = exports.API_PROJECT_ROBOT_TRIGGER_URL = exports.API_PROJECT_ROBOT_BUTTON_URL = exports.API_PROJECT_ROBOT_COMMAND2_URL = exports.API_PROJECT_ROBOT_COMMAND_URL = exports.API_PROJECT_ROBOT_AGENT_URL = exports.API_PROJECT_ROBOT_SETTING_URL = exports.API_PROJECT_ROBOT_EVENT_HISTORY_URL = void 0;
5
- exports.API_PROJECT_ROBOT_DEPLOYED_WORKFLOW_URL = exports.API_PROJECT_PROFILE_DEPLOYED_WORKFLOW_URL = exports.API_PROJECT_ROBOT_NO_PROFILE_DEPLOYMENTS_URL = exports.API_PROJECT_PROFILE_DEPLOYMENTS_URL = exports.API_PROJECT_ROBOT_DEPLOYMENTS_URL = exports.API_PROJECT_WORKFLOW_ASSET_ID_URL = exports.API_PROJECT_WORKFLOW_ASSET_URL = exports.API_PROJECT_WORKFLOW_ID_URL = exports.API_PROJECT_WORKFLOW_URL = exports.API_GRAPHS_ASSETS_URL = exports.API_GRAPHS_ASSETS_UPLOAD_URL = exports.API_GRAPHS_TARGETS_URL = exports.API_GRAPHS_TARGET_UPLOAD_URL = exports.API_GRAPHS_OBSERVATION_KEYS_URL = exports.API_GRAPHS_OBSERVATIONS_URL = exports.API_GRAPHS_PANORAMA_OBSERVATIONS_URL = exports.API_GRAPHS_PANORAMA = exports.API_GRAPHS_MAPS_GEOJSON_URL = exports.API_GRAPHS_MAPS_DEPLOY_URL = exports.API_GRAPHS_MAPS_COPY_URL = exports.API_GRAPHS_MAP_METADATA_URL = exports.API_GRAPHS_MAP_CONTENT_URL = exports.API_GRAPHS_MAP_ID_URL = exports.API_GRAPHS_MAPS_MERGE_URL = exports.API_GRAPHS_MAPS_DEPLOYED_URL = exports.API_GRAPHS_MAPS_NEW_URL = exports.API_GRAPHS_MAPS_URL = exports.API_DD_INTEGRATION_LEVELS_URL = exports.API_DD_INTEGRATION_LOCATIONS_URL = exports.API_DD_INTEGRATION_ISSUES_URL = exports.API_DD_INTEGRATION_OVERLAYS_URL = exports.API_DD_INTEGRATION_PLAN_BY_ID_URL = exports.API_DD_INTEGRATION_PLANS_URL = exports.API_SPOTTY_URL = exports.API_PROJECT_SCHEDULES_URL = exports.API_SOURCE_ID_URL = exports.API_SOURCE_URL = exports.API_SOURCE_SCHEMA_URL = exports.API_TEMPLATE_EXPORTER_URL = exports.API_TEMPLATE_PROVISION_ID_URL = exports.API_TEMPLATE_PROVISION_URL = exports.API_TEMPLATE_DEPLOY_URL = exports.API_PROJECT_PROFILE_DASHBOARD_CUSTOM_WIDGET_URL = exports.API_PROJECT_PROFILE_DASHBOARD_ID_URL = exports.API_PROJECT_PROFILE_DASHBOARD_URL = exports.API_PROJECT_CALLSIGN_STREAM_URL = exports.API_PROJECT_ROBOT_DASHBOARD_CUSTOM_WIDGET_URL = exports.API_PROJECT_ROBOT_DASHBOARD_ID_URL = exports.API_PROJECT_ROBOT_DASHBOARD_URL = exports.API_PROJECT_STREAM_CALLSIGN_URL = void 0;
6
- exports.API_PROJECT_ROBOT_TAG_URL = exports.API_PROJECT_PROFILE_TAG_URL = exports.API_PROJECT_PROFILE_TAGS_URL = exports.API_PROJECT_TAG_ROBOTS_URL = exports.API_PROJECT_ROBOT_TAGS_URL = exports.API_DEVICE_CREDENTIALS_AUTH_URL = exports.API_DEVICE_CREDENTIALS_URL = exports.API_LINKED_PROJECT_URL = exports.API_PROJECT_WORKFLOW_IMPORT_URL = exports.API_PROJECT_WORKFLOW_EXPORT_URL = exports.API_PROJECT_WORKFLOW_AFFECTED_URL = void 0;
5
+ exports.API_PROJECT_PROFILE_DEPLOYED_WORKFLOW_URL = exports.API_PROJECT_ROBOT_NO_PROFILE_DEPLOYMENTS_URL = exports.API_PROJECT_PROFILE_DEPLOYMENTS_URL = exports.API_PROJECT_ROBOT_DEPLOYMENTS_URL = exports.API_PROJECT_WORKFLOW_ASSET_ID_URL = exports.API_PROJECT_WORKFLOW_ASSET_URL = exports.API_PROJECT_WORKFLOW_ID_URL = exports.API_PROJECT_WORKFLOW_URL = exports.API_GRAPHS_ASSETS_URL = exports.API_GRAPHS_ASSETS_UPLOAD_URL = exports.API_GRAPHS_TARGETS_URL = exports.API_GRAPHS_TARGET_UPLOAD_URL = exports.API_GRAPHS_OBSERVATION_KEYS_URL = exports.API_GRAPHS_OBSERVATIONS_URL = exports.API_GRAPHS_PANORAMA_OBSERVATIONS_URL = exports.API_GRAPHS_PANORAMA = exports.API_GRAPHS_PANORAMAS_URL = exports.API_GRAPHS_MAPS_GEOJSON_URL = exports.API_GRAPHS_MAPS_DEPLOY_URL = exports.API_GRAPHS_MAPS_COPY_URL = exports.API_GRAPHS_MAP_METADATA_URL = exports.API_GRAPHS_MAP_CONTENT_URL = exports.API_GRAPHS_MAP_ID_URL = exports.API_GRAPHS_MAPS_MERGE_URL = exports.API_GRAPHS_MAPS_DEPLOYED_URL = exports.API_GRAPHS_MAPS_NEW_URL = exports.API_GRAPHS_MAPS_URL = exports.API_DD_INTEGRATION_LEVELS_URL = exports.API_DD_INTEGRATION_LOCATIONS_URL = exports.API_DD_INTEGRATION_ISSUES_URL = exports.API_DD_INTEGRATION_OVERLAYS_URL = exports.API_DD_INTEGRATION_PLAN_BY_ID_URL = exports.API_DD_INTEGRATION_PLANS_URL = exports.API_SPOTTY_URL = exports.API_PROJECT_SCHEDULES_URL = exports.API_SOURCE_ID_URL = exports.API_SOURCE_URL = exports.API_SOURCE_SCHEMA_URL = exports.API_TEMPLATE_EXPORTER_URL = exports.API_TEMPLATE_PROVISION_ID_URL = exports.API_TEMPLATE_PROVISION_URL = exports.API_TEMPLATE_DEPLOY_URL = exports.API_PROJECT_PROFILE_DASHBOARD_CUSTOM_WIDGET_URL = exports.API_PROJECT_PROFILE_DASHBOARD_ID_URL = exports.API_PROJECT_PROFILE_DASHBOARD_URL = exports.API_PROJECT_CALLSIGN_STREAM_URL = exports.API_PROJECT_ROBOT_DASHBOARD_CUSTOM_WIDGET_URL = exports.API_PROJECT_ROBOT_DASHBOARD_ID_URL = exports.API_PROJECT_ROBOT_DASHBOARD_URL = exports.API_PROJECT_STREAM_CALLSIGN_URL = void 0;
6
+ exports.API_PROJECT_ROBOT_TAG_URL = exports.API_PROJECT_PROFILE_TAG_URL = exports.API_PROJECT_PROFILE_TAGS_URL = exports.API_PROJECT_TAG_ROBOTS_URL = exports.API_PROJECT_ROBOT_TAGS_URL = exports.API_DEVICE_CREDENTIALS_AUTH_URL = exports.API_DEVICE_CREDENTIALS_URL = exports.API_LINKED_PROJECT_URL = exports.API_PROJECT_WORKFLOW_IMPORT_URL = exports.API_PROJECT_WORKFLOW_EXPORT_URL = exports.API_PROJECT_WORKFLOW_AFFECTED_URL = exports.API_PROJECT_ROBOT_DEPLOYED_WORKFLOW_URL = void 0;
7
7
  exports.API_APPLICATION_AUTH_URL = 'https://{url}/applications/auth';
8
8
  exports.API_ADMIN_USER_INVITATION_URL = 'https://{url}/admin/users/invitations';
9
9
  exports.API_USER_URL = 'https://{url}/users';
@@ -137,6 +137,7 @@ exports.API_GRAPHS_MAP_METADATA_URL = 'https://{url}/graphs/projects/{projectId}
137
137
  exports.API_GRAPHS_MAPS_COPY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy';
138
138
  exports.API_GRAPHS_MAPS_DEPLOY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy';
139
139
  exports.API_GRAPHS_MAPS_GEOJSON_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson';
140
+ exports.API_GRAPHS_PANORAMAS_URL = 'https://{url}/graphs/projects/{projectId}/panoramas';
140
141
  exports.API_GRAPHS_PANORAMA = 'https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}';
141
142
  exports.API_GRAPHS_PANORAMA_OBSERVATIONS_URL = 'https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}/observations';
142
143
  exports.API_GRAPHS_OBSERVATIONS_URL = 'https://{url}/graphs/projects/{projectId}/observations';
@@ -0,0 +1,25 @@
1
+ import { RobotStatus, RobotStatusColour } from '../models/robot-status/RobotStatus';
2
+ /**
3
+ * Derives the canonical status-indicator colour from a robot's status, as a
4
+ * pure function of its health, readiness, and connectivity.
5
+ *
6
+ * Connectivity gates first — reported health is not trusted when connectivity is
7
+ * impaired — then health, then readiness:
8
+ *
9
+ * | Condition | Colour |
10
+ * | ---------------------------------------- | ------------------- |
11
+ * | connectivity `OFFLINE` | solid gray |
12
+ * | connectivity `DEGRADED` | flashing red/gray |
13
+ * | health `CRITICAL` | solid red |
14
+ * | health `ABNORMAL` | solid yellow |
15
+ * | health `UNKNOWN` | flashing green/gray |
16
+ * | health `NORMAL` + readiness `BUSY` | solid blue |
17
+ * | health `NORMAL` + readiness `IDLE`/unkn. | solid green |
18
+ *
19
+ * Legacy robots (heartbeat-only) report `NORMAL`/`IDLE`, so they resolve to
20
+ * solid green and never reach the flashing-green/gray "health unknown" case.
21
+ *
22
+ * This is the single source of truth for indicator colour; it is surfaced as
23
+ * `RobotStatusService.colourFor()`.
24
+ */
25
+ export declare const getRobotStatusColour: (status: Pick<RobotStatus, "health" | "readiness" | "connectivity">) => RobotStatusColour;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRobotStatusColour = void 0;
4
+ const RobotStatusEnums_1 = require("../models/robot-status/RobotStatusEnums");
5
+ const GRAY = { kind: 'solid', token: 'gray' };
6
+ const RED = { kind: 'solid', token: 'red' };
7
+ const YELLOW = { kind: 'solid', token: 'yellow' };
8
+ const BLUE = { kind: 'solid', token: 'blue' };
9
+ const GREEN = { kind: 'solid', token: 'green' };
10
+ const FLASHING_RED_GRAY = { kind: 'flashing', tokens: ['red', 'gray'] };
11
+ const FLASHING_GREEN_GRAY = { kind: 'flashing', tokens: ['green', 'gray'] };
12
+ /**
13
+ * Derives the canonical status-indicator colour from a robot's status, as a
14
+ * pure function of its health, readiness, and connectivity.
15
+ *
16
+ * Connectivity gates first — reported health is not trusted when connectivity is
17
+ * impaired — then health, then readiness:
18
+ *
19
+ * | Condition | Colour |
20
+ * | ---------------------------------------- | ------------------- |
21
+ * | connectivity `OFFLINE` | solid gray |
22
+ * | connectivity `DEGRADED` | flashing red/gray |
23
+ * | health `CRITICAL` | solid red |
24
+ * | health `ABNORMAL` | solid yellow |
25
+ * | health `UNKNOWN` | flashing green/gray |
26
+ * | health `NORMAL` + readiness `BUSY` | solid blue |
27
+ * | health `NORMAL` + readiness `IDLE`/unkn. | solid green |
28
+ *
29
+ * Legacy robots (heartbeat-only) report `NORMAL`/`IDLE`, so they resolve to
30
+ * solid green and never reach the flashing-green/gray "health unknown" case.
31
+ *
32
+ * This is the single source of truth for indicator colour; it is surfaced as
33
+ * `RobotStatusService.colourFor()`.
34
+ */
35
+ const getRobotStatusColour = (status) => {
36
+ const { health, readiness, connectivity } = status;
37
+ if (connectivity.overall === RobotStatusEnums_1.RobotConnectivity.OFFLINE)
38
+ return GRAY;
39
+ if (connectivity.overall === RobotStatusEnums_1.RobotConnectivity.DEGRADED)
40
+ return FLASHING_RED_GRAY;
41
+ // Connectivity is ONLINE: derive from reported health, then readiness.
42
+ switch (health) {
43
+ case RobotStatusEnums_1.RobotHealth.CRITICAL:
44
+ return RED;
45
+ case RobotStatusEnums_1.RobotHealth.ABNORMAL:
46
+ return YELLOW;
47
+ case RobotStatusEnums_1.RobotHealth.UNKNOWN:
48
+ return FLASHING_GREEN_GRAY;
49
+ case RobotStatusEnums_1.RobotHealth.NORMAL:
50
+ default:
51
+ return readiness === RobotStatusEnums_1.RobotReadiness.BUSY ? BLUE : GREEN;
52
+ }
53
+ };
54
+ exports.getRobotStatusColour = getRobotStatusColour;
@@ -5,3 +5,4 @@ export * from './getURLSearchParams';
5
5
  export * from './websandbox';
6
6
  export * from './kscript';
7
7
  export * from './splitRobotTopic';
8
+ export * from './getRobotStatusColour';
@@ -21,3 +21,4 @@ __exportStar(require("./getURLSearchParams"), exports);
21
21
  __exportStar(require("./websandbox"), exports);
22
22
  __exportStar(require("./kscript"), exports);
23
23
  __exportStar(require("./splitRobotTopic"), exports);
24
+ __exportStar(require("./getRobotStatusColour"), exports);
@@ -65,6 +65,8 @@ export * from './Robot';
65
65
  export * from './RobotConfig';
66
66
  export * from './RobotPlugin';
67
67
  export * from './RobotProfile';
68
+ export * from './robot-status/RobotStatus';
69
+ export * from './robot-status/RobotStatusEnums';
68
70
  export * from './RobotTemplate';
69
71
  export * from './RocosError';
70
72
  export * from './schedule/IScheduleAction';
@@ -81,6 +81,8 @@ __exportStar(require("./Robot"), exports);
81
81
  __exportStar(require("./RobotConfig"), exports);
82
82
  __exportStar(require("./RobotPlugin"), exports);
83
83
  __exportStar(require("./RobotProfile"), exports);
84
+ __exportStar(require("./robot-status/RobotStatus"), exports);
85
+ __exportStar(require("./robot-status/RobotStatusEnums"), exports);
84
86
  __exportStar(require("./RobotTemplate"), exports);
85
87
  __exportStar(require("./RocosError"), exports);
86
88
  __exportStar(require("./schedule/IScheduleAction"), exports);
@@ -24,4 +24,22 @@ export interface Panorama {
24
24
  path: string;
25
25
  };
26
26
  }
27
+ /**
28
+ * Body for `PUT /graphs/projects/{projectId}/panoramas`. Same shape as {@link Panorama}, with
29
+ * an optional `map` field that accepts either a single map id or an array of map ids.
30
+ *
31
+ * - The dronedeploy map is always written; values in `map` are added on top of it
32
+ * (deduped). Each named map must already exist server-side; a typo is rejected with 400.
33
+ * - `transform.id` may be left blank ('') to have the server generate a UUID; the returned
34
+ * {@link AddPanoramaResponse.id} echoes whichever value the panorama was created under.
35
+ * - `transform.parent` is created as a FRAME node when it doesn't already exist anywhere
36
+ * in the project, so callers don't need to bootstrap the parent before posting.
37
+ */
38
+ export interface AddPanoramaRequest extends Panorama {
39
+ map?: string | string[];
40
+ }
41
+ export interface AddPanoramaResponse {
42
+ /** Panorama node id — either the value the caller supplied, or the UUID the server generated. */
43
+ id: string;
44
+ }
27
45
  export {};
@@ -0,0 +1,43 @@
1
+ import { RobotConnectivity, RobotHealth, RobotReadiness, ServiceConnection } from './RobotStatusEnums';
2
+ /** The semantic colour tokens a status indicator can use. */
3
+ export type RobotStatusColourToken = 'gray' | 'green' | 'blue' | 'yellow' | 'red';
4
+ /**
5
+ * The canonical colour a status indicator should display, as a semantic token
6
+ * rather than a concrete colour — each consumer maps the token to its own theme.
7
+ *
8
+ * "Flashing" is structural rather than a single value: a degraded robot flashes
9
+ * red/gray, while an online robot whose health is explicitly unknown flashes
10
+ * green/gray.
11
+ */
12
+ export type RobotStatusColour = {
13
+ kind: 'solid';
14
+ token: RobotStatusColourToken;
15
+ } | {
16
+ kind: 'flashing';
17
+ tokens: ['red', 'gray'];
18
+ } | {
19
+ kind: 'flashing';
20
+ tokens: ['green', 'gray'];
21
+ };
22
+ /**
23
+ * The robot's connectivity to the cloud platform: an aggregate verdict plus the
24
+ * per-service breakdown it was derived from. Only the *expected* services for a
25
+ * given robot are present in `services`.
26
+ */
27
+ export interface RobotConnectivityStatus {
28
+ overall: RobotConnectivity;
29
+ /** Keyed by service id (e.g. `robot-configs`, `robot-services`, `telemetry-liveness`). */
30
+ services: Record<string, ServiceConnection>;
31
+ }
32
+ /**
33
+ * The combined, canonical status of a robot: what the robot reports about itself
34
+ * (health + readiness), its connectivity, and the resulting indicator colour.
35
+ *
36
+ * This is the object emitted by `RobotStatusService.getRobotStatusChanges()`.
37
+ */
38
+ export interface RobotStatus {
39
+ health: RobotHealth;
40
+ readiness: RobotReadiness;
41
+ connectivity: RobotConnectivityStatus;
42
+ colour: RobotStatusColour;
43
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The health of a robot, as reported by the agent's `robot/status` topic.
3
+ *
4
+ * The string values are the SDK-facing representation; the agent encodes these
5
+ * as integers on the wire (shown below). The {@link RobotStatusService} maps
6
+ * the integer wire values onto these enums on receipt.
7
+ */
8
+ export declare enum RobotHealth {
9
+ /** `0` on the wire. Health has not been determined. */
10
+ UNKNOWN = "unknown",
11
+ /** `1` on the wire. The robot is healthy. */
12
+ NORMAL = "normal",
13
+ /** `2` on the wire. Something needs attention, but the robot is still functional. */
14
+ ABNORMAL = "abnormal",
15
+ /** `3` on the wire. The robot requires immediate attention. */
16
+ CRITICAL = "critical"
17
+ }
18
+ /**
19
+ * The readiness of a robot — whether it is available to take on work — as
20
+ * reported by the agent's `robot/status` topic.
21
+ *
22
+ * As with {@link RobotHealth}, the agent encodes these as integers on the wire.
23
+ */
24
+ export declare enum RobotReadiness {
25
+ /** `0` on the wire. Readiness has not been determined. */
26
+ UNKNOWN = "unknown",
27
+ /** `1` on the wire. The robot is available. */
28
+ IDLE = "idle",
29
+ /** `2` on the wire. The robot is occupied and should not be interrupted. */
30
+ BUSY = "busy"
31
+ }
32
+ /**
33
+ * Whether the robot is connected to a single cloud service, as reported by that
34
+ * service's `connections` endpoint (or, for `telemetry-liveness`, derived from
35
+ * heartbeat freshness).
36
+ */
37
+ export declare enum ServiceConnection {
38
+ CONNECTED = "connected",
39
+ DISCONNECTED = "disconnected",
40
+ /** The service's connectivity has not yet been determined (e.g. not polled). */
41
+ UNKNOWN = "unknown"
42
+ }
43
+ /**
44
+ * The robot's overall connectivity to the cloud platform, aggregated across all
45
+ * expected services.
46
+ */
47
+ export declare enum RobotConnectivity {
48
+ /** Every expected service reports connected. */
49
+ ONLINE = "online",
50
+ /** Some, but not all, expected services report connected. */
51
+ DEGRADED = "degraded",
52
+ /** No expected service reports connected. */
53
+ OFFLINE = "offline"
54
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RobotConnectivity = exports.ServiceConnection = exports.RobotReadiness = exports.RobotHealth = void 0;
4
+ /**
5
+ * The health of a robot, as reported by the agent's `robot/status` topic.
6
+ *
7
+ * The string values are the SDK-facing representation; the agent encodes these
8
+ * as integers on the wire (shown below). The {@link RobotStatusService} maps
9
+ * the integer wire values onto these enums on receipt.
10
+ */
11
+ var RobotHealth;
12
+ (function (RobotHealth) {
13
+ /** `0` on the wire. Health has not been determined. */
14
+ RobotHealth["UNKNOWN"] = "unknown";
15
+ /** `1` on the wire. The robot is healthy. */
16
+ RobotHealth["NORMAL"] = "normal";
17
+ /** `2` on the wire. Something needs attention, but the robot is still functional. */
18
+ RobotHealth["ABNORMAL"] = "abnormal";
19
+ /** `3` on the wire. The robot requires immediate attention. */
20
+ RobotHealth["CRITICAL"] = "critical";
21
+ })(RobotHealth || (exports.RobotHealth = RobotHealth = {}));
22
+ /**
23
+ * The readiness of a robot — whether it is available to take on work — as
24
+ * reported by the agent's `robot/status` topic.
25
+ *
26
+ * As with {@link RobotHealth}, the agent encodes these as integers on the wire.
27
+ */
28
+ var RobotReadiness;
29
+ (function (RobotReadiness) {
30
+ /** `0` on the wire. Readiness has not been determined. */
31
+ RobotReadiness["UNKNOWN"] = "unknown";
32
+ /** `1` on the wire. The robot is available. */
33
+ RobotReadiness["IDLE"] = "idle";
34
+ /** `2` on the wire. The robot is occupied and should not be interrupted. */
35
+ RobotReadiness["BUSY"] = "busy";
36
+ })(RobotReadiness || (exports.RobotReadiness = RobotReadiness = {}));
37
+ /**
38
+ * Whether the robot is connected to a single cloud service, as reported by that
39
+ * service's `connections` endpoint (or, for `telemetry-liveness`, derived from
40
+ * heartbeat freshness).
41
+ */
42
+ var ServiceConnection;
43
+ (function (ServiceConnection) {
44
+ ServiceConnection["CONNECTED"] = "connected";
45
+ ServiceConnection["DISCONNECTED"] = "disconnected";
46
+ /** The service's connectivity has not yet been determined (e.g. not polled). */
47
+ ServiceConnection["UNKNOWN"] = "unknown";
48
+ })(ServiceConnection || (exports.ServiceConnection = ServiceConnection = {}));
49
+ /**
50
+ * The robot's overall connectivity to the cloud platform, aggregated across all
51
+ * expected services.
52
+ */
53
+ var RobotConnectivity;
54
+ (function (RobotConnectivity) {
55
+ /** Every expected service reports connected. */
56
+ RobotConnectivity["ONLINE"] = "online";
57
+ /** Some, but not all, expected services report connected. */
58
+ RobotConnectivity["DEGRADED"] = "degraded";
59
+ /** No expected service reports connected. */
60
+ RobotConnectivity["OFFLINE"] = "offline";
61
+ })(RobotConnectivity || (exports.RobotConnectivity = RobotConnectivity = {}));
@@ -43,6 +43,44 @@ export declare class CallerService extends BaseStreamService<ICallerStream> {
43
43
  ack$: Observable<IRocosCallerMessageResponseAck>;
44
44
  cancel: () => Promise<void>;
45
45
  };
46
+ /** Invoke a long-running action (ROS 2 action-server semantics) and expose its lifecycle safely.
47
+ *
48
+ * Use this instead of `call` when the request is *accepted* (ack) long before it
49
+ * *completes* (result) — e.g. a navigation goal or a mission. The semantics are:
50
+ * fire the request exactly once, hold the underlying stream open after the ack,
51
+ * and tear it down only when the action itself completes/errors.
52
+ *
53
+ * This differs from `call` in one crucial way: `call` builds `ack$`/`result$` on a
54
+ * refcounted shared source, so awaiting `ack$` (dropping the subscriber count to
55
+ * zero) and *then* subscribing to `result$` re-issues the goal. `callAction` pins the
56
+ * source with a single SDK-owned subscription for the action's lifetime, so:
57
+ * - the request fires once and is never re-issued by subscriber churn,
58
+ * - `ack` is a Promise (inherently replayable — await it in any order),
59
+ * - `result$` replays the one-shot result, so a late or out-of-order subscriber
60
+ * still receives it.
61
+ *
62
+ * Lifecycle:
63
+ * - `ack` resolves with the first acknowledgement; rejects if the action
64
+ * errors (or completes) before any ack arrives.
65
+ * - `result$` emits the single result and completes when the action ends. Replayed,
66
+ * so subscription order relative to awaiting `ack` does not matter.
67
+ * - `return$` streams live feedback/return payloads (decoded as `T`). Not replayed —
68
+ * subscribe before the action emits feedback to avoid missing it.
69
+ * - `cancel` asks the server to cancel; the action then emits its result and closes.
70
+ * - `close` stops tracking the action locally *without* cancelling it on the robot,
71
+ * releasing the underlying stream. For teardown paths (e.g. UI unmount)
72
+ * where the action should keep running but the result is no longer needed.
73
+ *
74
+ * @see call
75
+ * @see callRaw
76
+ */
77
+ callAction<T = unknown>(params: ICallerCallParams): {
78
+ ack: Promise<IRocosCallerMessageResponseAck>;
79
+ result$: Observable<IRocosCallerMessageResponseResult>;
80
+ return$: Observable<T>;
81
+ cancel: () => Promise<void>;
82
+ close: () => void;
83
+ };
46
84
  protected createStream(): Promise<ICallerStream>;
47
85
  protected getStream(config: IStreamConfig): ICallerStream;
48
86
  }
@@ -104,6 +104,62 @@ class CallerService extends BaseStreamService_1.BaseStreamService {
104
104
  cancel,
105
105
  };
106
106
  }
107
+ /** Invoke a long-running action (ROS 2 action-server semantics) and expose its lifecycle safely.
108
+ *
109
+ * Use this instead of `call` when the request is *accepted* (ack) long before it
110
+ * *completes* (result) — e.g. a navigation goal or a mission. The semantics are:
111
+ * fire the request exactly once, hold the underlying stream open after the ack,
112
+ * and tear it down only when the action itself completes/errors.
113
+ *
114
+ * This differs from `call` in one crucial way: `call` builds `ack$`/`result$` on a
115
+ * refcounted shared source, so awaiting `ack$` (dropping the subscriber count to
116
+ * zero) and *then* subscribing to `result$` re-issues the goal. `callAction` pins the
117
+ * source with a single SDK-owned subscription for the action's lifetime, so:
118
+ * - the request fires once and is never re-issued by subscriber churn,
119
+ * - `ack` is a Promise (inherently replayable — await it in any order),
120
+ * - `result$` replays the one-shot result, so a late or out-of-order subscriber
121
+ * still receives it.
122
+ *
123
+ * Lifecycle:
124
+ * - `ack` resolves with the first acknowledgement; rejects if the action
125
+ * errors (or completes) before any ack arrives.
126
+ * - `result$` emits the single result and completes when the action ends. Replayed,
127
+ * so subscription order relative to awaiting `ack` does not matter.
128
+ * - `return$` streams live feedback/return payloads (decoded as `T`). Not replayed —
129
+ * subscribe before the action emits feedback to avoid missing it.
130
+ * - `cancel` asks the server to cancel; the action then emits its result and closes.
131
+ * - `close` stops tracking the action locally *without* cancelling it on the robot,
132
+ * releasing the underlying stream. For teardown paths (e.g. UI unmount)
133
+ * where the action should keep running but the result is no longer needed.
134
+ *
135
+ * @see call
136
+ * @see callRaw
137
+ */
138
+ callAction(params) {
139
+ const stream = this.call(params);
140
+ // Replay the one-shot result so subscription order never matters and a late
141
+ // subscriber still receives it.
142
+ const result = new rxjs_1.ReplaySubject(1);
143
+ // One SDK-owned subscription pins the shared source alive for the whole action.
144
+ // It fires the request once (first subscriber) and forwards the result into the
145
+ // replay subject, completing/erroring it when the action ends. Because this
146
+ // subscription outlives any `firstValueFrom(ack)` teardown, subscriber churn can
147
+ // never reset the source and re-issue the goal.
148
+ const pin = stream.result$.subscribe(result);
149
+ // `ack` rejects if the action errors or completes before any ack arrives. Since
150
+ // callAction is meant to be consumed via result$/return$ too, a caller may never
151
+ // touch `ack` — without a handler that rejection would surface as an unhandled
152
+ // promise rejection. Awaiting `action.ack` still rejects for callers who do care.
153
+ const ack = (0, rxjs_1.firstValueFrom)(stream.ack$);
154
+ ack.catch(() => { });
155
+ return {
156
+ ack,
157
+ result$: result.asObservable(),
158
+ return$: stream.return$,
159
+ cancel: stream.cancel,
160
+ close: () => pin.unsubscribe(),
161
+ };
162
+ }
107
163
  async createStream() {
108
164
  return (await this.createStreamFromConfig(identifier_1.IDENTIFIER_NAME_CALLER, {
109
165
  url: this.config.url,
@@ -1,5 +1,5 @@
1
+ import { AddPanoramaRequest, AddPanoramaResponse, CreateObservation, Observation } from '../models/maps/Panorama';
1
2
  import { Asset, IBaseService, IRocosSDKConfig, Map, MapContent, RocosError } from '../models';
2
- import { CreateObservation, Observation } from '../models/maps/Panorama';
3
3
  import { BaseServiceAbstract } from './BaseServiceAbstract';
4
4
  /**
5
5
  * Maps service for managing robot maps in the cloud and on robots
@@ -202,6 +202,25 @@ export declare class MapService extends BaseServiceAbstract implements IBaseServ
202
202
  * @returns A list of assets
203
203
  */
204
204
  getAssetsKeys(projectId: string): Promise<string[]>;
205
+ /**
206
+ * Adds a panorama to the project's dronedeploy map (and optionally other named maps).
207
+ *
208
+ * The dronedeploy map is always written. To also write the panorama into additional maps,
209
+ * pass their ids in `body.map` (single string or array). Each named map must already exist —
210
+ * unknown ids reject the whole call with 400. Entries are deduplicated against dronedeploy
211
+ * and each other.
212
+ *
213
+ * Two server-side conveniences:
214
+ * - `body.transform.id` may be left blank ('') to have the server generate a UUID. The
215
+ * created id is returned in the response so the caller can subsequently get/delete it.
216
+ * - `body.transform.parent` is auto-created as a FRAME node when it doesn't already exist
217
+ * anywhere in the project; no separate "create parent frame" call is required.
218
+ *
219
+ * @param projectId The ID of the project the panorama belongs to.
220
+ * @param body Panorama transform + data, with an optional `map` selector.
221
+ * @returns The panorama node id that was created (echoed when supplied, generated when blank).
222
+ */
223
+ addPanorama(projectId: string, body: AddPanoramaRequest): Promise<AddPanoramaResponse>;
205
224
  /**
206
225
  * Deletes a panorama by panoramaID.
207
226
  *
@@ -282,6 +282,27 @@ class MapService extends BaseServiceAbstract_1.BaseServiceAbstract {
282
282
  getAssetsKeys(projectId) {
283
283
  return this.callGet((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_OBSERVATION_KEYS_URL, { url: this.config.url, projectId }, this.config.insecure), 'Failed to get asset keys.');
284
284
  }
285
+ /**
286
+ * Adds a panorama to the project's dronedeploy map (and optionally other named maps).
287
+ *
288
+ * The dronedeploy map is always written. To also write the panorama into additional maps,
289
+ * pass their ids in `body.map` (single string or array). Each named map must already exist —
290
+ * unknown ids reject the whole call with 400. Entries are deduplicated against dronedeploy
291
+ * and each other.
292
+ *
293
+ * Two server-side conveniences:
294
+ * - `body.transform.id` may be left blank ('') to have the server generate a UUID. The
295
+ * created id is returned in the response so the caller can subsequently get/delete it.
296
+ * - `body.transform.parent` is auto-created as a FRAME node when it doesn't already exist
297
+ * anywhere in the project; no separate "create parent frame" call is required.
298
+ *
299
+ * @param projectId The ID of the project the panorama belongs to.
300
+ * @param body Panorama transform + data, with an optional `map` selector.
301
+ * @returns The panorama node id that was created (echoed when supplied, generated when blank).
302
+ */
303
+ addPanorama(projectId, body) {
304
+ return this.callPut((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_PANORAMAS_URL, { url: this.config.url, projectId }, this.config.insecure), body, 'Failed to add panorama.');
305
+ }
285
306
  /**
286
307
  * Deletes a panorama by panoramaID.
287
308
  *
@@ -131,6 +131,7 @@ export declare const API_GRAPHS_MAP_METADATA_URL = "https://{url}/graphs/project
131
131
  export declare const API_GRAPHS_MAPS_COPY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy";
132
132
  export declare const API_GRAPHS_MAPS_DEPLOY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy";
133
133
  export declare const API_GRAPHS_MAPS_GEOJSON_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson";
134
+ export declare const API_GRAPHS_PANORAMAS_URL = "https://{url}/graphs/projects/{projectId}/panoramas";
134
135
  export declare const API_GRAPHS_PANORAMA = "https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}";
135
136
  export declare const API_GRAPHS_PANORAMA_OBSERVATIONS_URL = "https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}/observations";
136
137
  export declare const API_GRAPHS_OBSERVATIONS_URL = "https://{url}/graphs/projects/{projectId}/observations";
@@ -131,6 +131,7 @@ export const API_GRAPHS_MAP_METADATA_URL = 'https://{url}/graphs/projects/{proje
131
131
  export const API_GRAPHS_MAPS_COPY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy';
132
132
  export const API_GRAPHS_MAPS_DEPLOY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy';
133
133
  export const API_GRAPHS_MAPS_GEOJSON_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson';
134
+ export const API_GRAPHS_PANORAMAS_URL = 'https://{url}/graphs/projects/{projectId}/panoramas';
134
135
  export const API_GRAPHS_PANORAMA = 'https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}';
135
136
  export const API_GRAPHS_PANORAMA_OBSERVATIONS_URL = 'https://{url}/graphs/projects/{projectId}/panoramas/{panoramaId}/observations';
136
137
  export const API_GRAPHS_OBSERVATIONS_URL = 'https://{url}/graphs/projects/{projectId}/observations';
@@ -0,0 +1,25 @@
1
+ import { RobotStatus, RobotStatusColour } from '../models/robot-status/RobotStatus';
2
+ /**
3
+ * Derives the canonical status-indicator colour from a robot's status, as a
4
+ * pure function of its health, readiness, and connectivity.
5
+ *
6
+ * Connectivity gates first — reported health is not trusted when connectivity is
7
+ * impaired — then health, then readiness:
8
+ *
9
+ * | Condition | Colour |
10
+ * | ---------------------------------------- | ------------------- |
11
+ * | connectivity `OFFLINE` | solid gray |
12
+ * | connectivity `DEGRADED` | flashing red/gray |
13
+ * | health `CRITICAL` | solid red |
14
+ * | health `ABNORMAL` | solid yellow |
15
+ * | health `UNKNOWN` | flashing green/gray |
16
+ * | health `NORMAL` + readiness `BUSY` | solid blue |
17
+ * | health `NORMAL` + readiness `IDLE`/unkn. | solid green |
18
+ *
19
+ * Legacy robots (heartbeat-only) report `NORMAL`/`IDLE`, so they resolve to
20
+ * solid green and never reach the flashing-green/gray "health unknown" case.
21
+ *
22
+ * This is the single source of truth for indicator colour; it is surfaced as
23
+ * `RobotStatusService.colourFor()`.
24
+ */
25
+ export declare const getRobotStatusColour: (status: Pick<RobotStatus, "health" | "readiness" | "connectivity">) => RobotStatusColour;
@@ -0,0 +1,50 @@
1
+ import { RobotConnectivity, RobotHealth, RobotReadiness } from '../models/robot-status/RobotStatusEnums';
2
+ const GRAY = { kind: 'solid', token: 'gray' };
3
+ const RED = { kind: 'solid', token: 'red' };
4
+ const YELLOW = { kind: 'solid', token: 'yellow' };
5
+ const BLUE = { kind: 'solid', token: 'blue' };
6
+ const GREEN = { kind: 'solid', token: 'green' };
7
+ const FLASHING_RED_GRAY = { kind: 'flashing', tokens: ['red', 'gray'] };
8
+ const FLASHING_GREEN_GRAY = { kind: 'flashing', tokens: ['green', 'gray'] };
9
+ /**
10
+ * Derives the canonical status-indicator colour from a robot's status, as a
11
+ * pure function of its health, readiness, and connectivity.
12
+ *
13
+ * Connectivity gates first — reported health is not trusted when connectivity is
14
+ * impaired — then health, then readiness:
15
+ *
16
+ * | Condition | Colour |
17
+ * | ---------------------------------------- | ------------------- |
18
+ * | connectivity `OFFLINE` | solid gray |
19
+ * | connectivity `DEGRADED` | flashing red/gray |
20
+ * | health `CRITICAL` | solid red |
21
+ * | health `ABNORMAL` | solid yellow |
22
+ * | health `UNKNOWN` | flashing green/gray |
23
+ * | health `NORMAL` + readiness `BUSY` | solid blue |
24
+ * | health `NORMAL` + readiness `IDLE`/unkn. | solid green |
25
+ *
26
+ * Legacy robots (heartbeat-only) report `NORMAL`/`IDLE`, so they resolve to
27
+ * solid green and never reach the flashing-green/gray "health unknown" case.
28
+ *
29
+ * This is the single source of truth for indicator colour; it is surfaced as
30
+ * `RobotStatusService.colourFor()`.
31
+ */
32
+ export const getRobotStatusColour = (status) => {
33
+ const { health, readiness, connectivity } = status;
34
+ if (connectivity.overall === RobotConnectivity.OFFLINE)
35
+ return GRAY;
36
+ if (connectivity.overall === RobotConnectivity.DEGRADED)
37
+ return FLASHING_RED_GRAY;
38
+ // Connectivity is ONLINE: derive from reported health, then readiness.
39
+ switch (health) {
40
+ case RobotHealth.CRITICAL:
41
+ return RED;
42
+ case RobotHealth.ABNORMAL:
43
+ return YELLOW;
44
+ case RobotHealth.UNKNOWN:
45
+ return FLASHING_GREEN_GRAY;
46
+ case RobotHealth.NORMAL:
47
+ default:
48
+ return readiness === RobotReadiness.BUSY ? BLUE : GREEN;
49
+ }
50
+ };
@@ -5,3 +5,4 @@ export * from './getURLSearchParams';
5
5
  export * from './websandbox';
6
6
  export * from './kscript';
7
7
  export * from './splitRobotTopic';
8
+ export * from './getRobotStatusColour';
@@ -5,3 +5,4 @@ export * from './getURLSearchParams';
5
5
  export * from './websandbox';
6
6
  export * from './kscript';
7
7
  export * from './splitRobotTopic';
8
+ export * from './getRobotStatusColour';
@@ -65,6 +65,8 @@ export * from './Robot';
65
65
  export * from './RobotConfig';
66
66
  export * from './RobotPlugin';
67
67
  export * from './RobotProfile';
68
+ export * from './robot-status/RobotStatus';
69
+ export * from './robot-status/RobotStatusEnums';
68
70
  export * from './RobotTemplate';
69
71
  export * from './RocosError';
70
72
  export * from './schedule/IScheduleAction';
@@ -65,6 +65,8 @@ export * from './Robot';
65
65
  export * from './RobotConfig';
66
66
  export * from './RobotPlugin';
67
67
  export * from './RobotProfile';
68
+ export * from './robot-status/RobotStatus';
69
+ export * from './robot-status/RobotStatusEnums';
68
70
  export * from './RobotTemplate';
69
71
  export * from './RocosError';
70
72
  export * from './schedule/IScheduleAction';
@@ -24,4 +24,22 @@ export interface Panorama {
24
24
  path: string;
25
25
  };
26
26
  }
27
+ /**
28
+ * Body for `PUT /graphs/projects/{projectId}/panoramas`. Same shape as {@link Panorama}, with
29
+ * an optional `map` field that accepts either a single map id or an array of map ids.
30
+ *
31
+ * - The dronedeploy map is always written; values in `map` are added on top of it
32
+ * (deduped). Each named map must already exist server-side; a typo is rejected with 400.
33
+ * - `transform.id` may be left blank ('') to have the server generate a UUID; the returned
34
+ * {@link AddPanoramaResponse.id} echoes whichever value the panorama was created under.
35
+ * - `transform.parent` is created as a FRAME node when it doesn't already exist anywhere
36
+ * in the project, so callers don't need to bootstrap the parent before posting.
37
+ */
38
+ export interface AddPanoramaRequest extends Panorama {
39
+ map?: string | string[];
40
+ }
41
+ export interface AddPanoramaResponse {
42
+ /** Panorama node id — either the value the caller supplied, or the UUID the server generated. */
43
+ id: string;
44
+ }
27
45
  export {};
@@ -0,0 +1,43 @@
1
+ import { RobotConnectivity, RobotHealth, RobotReadiness, ServiceConnection } from './RobotStatusEnums';
2
+ /** The semantic colour tokens a status indicator can use. */
3
+ export type RobotStatusColourToken = 'gray' | 'green' | 'blue' | 'yellow' | 'red';
4
+ /**
5
+ * The canonical colour a status indicator should display, as a semantic token
6
+ * rather than a concrete colour — each consumer maps the token to its own theme.
7
+ *
8
+ * "Flashing" is structural rather than a single value: a degraded robot flashes
9
+ * red/gray, while an online robot whose health is explicitly unknown flashes
10
+ * green/gray.
11
+ */
12
+ export type RobotStatusColour = {
13
+ kind: 'solid';
14
+ token: RobotStatusColourToken;
15
+ } | {
16
+ kind: 'flashing';
17
+ tokens: ['red', 'gray'];
18
+ } | {
19
+ kind: 'flashing';
20
+ tokens: ['green', 'gray'];
21
+ };
22
+ /**
23
+ * The robot's connectivity to the cloud platform: an aggregate verdict plus the
24
+ * per-service breakdown it was derived from. Only the *expected* services for a
25
+ * given robot are present in `services`.
26
+ */
27
+ export interface RobotConnectivityStatus {
28
+ overall: RobotConnectivity;
29
+ /** Keyed by service id (e.g. `robot-configs`, `robot-services`, `telemetry-liveness`). */
30
+ services: Record<string, ServiceConnection>;
31
+ }
32
+ /**
33
+ * The combined, canonical status of a robot: what the robot reports about itself
34
+ * (health + readiness), its connectivity, and the resulting indicator colour.
35
+ *
36
+ * This is the object emitted by `RobotStatusService.getRobotStatusChanges()`.
37
+ */
38
+ export interface RobotStatus {
39
+ health: RobotHealth;
40
+ readiness: RobotReadiness;
41
+ connectivity: RobotConnectivityStatus;
42
+ colour: RobotStatusColour;
43
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The health of a robot, as reported by the agent's `robot/status` topic.
3
+ *
4
+ * The string values are the SDK-facing representation; the agent encodes these
5
+ * as integers on the wire (shown below). The {@link RobotStatusService} maps
6
+ * the integer wire values onto these enums on receipt.
7
+ */
8
+ export declare enum RobotHealth {
9
+ /** `0` on the wire. Health has not been determined. */
10
+ UNKNOWN = "unknown",
11
+ /** `1` on the wire. The robot is healthy. */
12
+ NORMAL = "normal",
13
+ /** `2` on the wire. Something needs attention, but the robot is still functional. */
14
+ ABNORMAL = "abnormal",
15
+ /** `3` on the wire. The robot requires immediate attention. */
16
+ CRITICAL = "critical"
17
+ }
18
+ /**
19
+ * The readiness of a robot — whether it is available to take on work — as
20
+ * reported by the agent's `robot/status` topic.
21
+ *
22
+ * As with {@link RobotHealth}, the agent encodes these as integers on the wire.
23
+ */
24
+ export declare enum RobotReadiness {
25
+ /** `0` on the wire. Readiness has not been determined. */
26
+ UNKNOWN = "unknown",
27
+ /** `1` on the wire. The robot is available. */
28
+ IDLE = "idle",
29
+ /** `2` on the wire. The robot is occupied and should not be interrupted. */
30
+ BUSY = "busy"
31
+ }
32
+ /**
33
+ * Whether the robot is connected to a single cloud service, as reported by that
34
+ * service's `connections` endpoint (or, for `telemetry-liveness`, derived from
35
+ * heartbeat freshness).
36
+ */
37
+ export declare enum ServiceConnection {
38
+ CONNECTED = "connected",
39
+ DISCONNECTED = "disconnected",
40
+ /** The service's connectivity has not yet been determined (e.g. not polled). */
41
+ UNKNOWN = "unknown"
42
+ }
43
+ /**
44
+ * The robot's overall connectivity to the cloud platform, aggregated across all
45
+ * expected services.
46
+ */
47
+ export declare enum RobotConnectivity {
48
+ /** Every expected service reports connected. */
49
+ ONLINE = "online",
50
+ /** Some, but not all, expected services report connected. */
51
+ DEGRADED = "degraded",
52
+ /** No expected service reports connected. */
53
+ OFFLINE = "offline"
54
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The health of a robot, as reported by the agent's `robot/status` topic.
3
+ *
4
+ * The string values are the SDK-facing representation; the agent encodes these
5
+ * as integers on the wire (shown below). The {@link RobotStatusService} maps
6
+ * the integer wire values onto these enums on receipt.
7
+ */
8
+ export var RobotHealth;
9
+ (function (RobotHealth) {
10
+ /** `0` on the wire. Health has not been determined. */
11
+ RobotHealth["UNKNOWN"] = "unknown";
12
+ /** `1` on the wire. The robot is healthy. */
13
+ RobotHealth["NORMAL"] = "normal";
14
+ /** `2` on the wire. Something needs attention, but the robot is still functional. */
15
+ RobotHealth["ABNORMAL"] = "abnormal";
16
+ /** `3` on the wire. The robot requires immediate attention. */
17
+ RobotHealth["CRITICAL"] = "critical";
18
+ })(RobotHealth || (RobotHealth = {}));
19
+ /**
20
+ * The readiness of a robot — whether it is available to take on work — as
21
+ * reported by the agent's `robot/status` topic.
22
+ *
23
+ * As with {@link RobotHealth}, the agent encodes these as integers on the wire.
24
+ */
25
+ export var RobotReadiness;
26
+ (function (RobotReadiness) {
27
+ /** `0` on the wire. Readiness has not been determined. */
28
+ RobotReadiness["UNKNOWN"] = "unknown";
29
+ /** `1` on the wire. The robot is available. */
30
+ RobotReadiness["IDLE"] = "idle";
31
+ /** `2` on the wire. The robot is occupied and should not be interrupted. */
32
+ RobotReadiness["BUSY"] = "busy";
33
+ })(RobotReadiness || (RobotReadiness = {}));
34
+ /**
35
+ * Whether the robot is connected to a single cloud service, as reported by that
36
+ * service's `connections` endpoint (or, for `telemetry-liveness`, derived from
37
+ * heartbeat freshness).
38
+ */
39
+ export var ServiceConnection;
40
+ (function (ServiceConnection) {
41
+ ServiceConnection["CONNECTED"] = "connected";
42
+ ServiceConnection["DISCONNECTED"] = "disconnected";
43
+ /** The service's connectivity has not yet been determined (e.g. not polled). */
44
+ ServiceConnection["UNKNOWN"] = "unknown";
45
+ })(ServiceConnection || (ServiceConnection = {}));
46
+ /**
47
+ * The robot's overall connectivity to the cloud platform, aggregated across all
48
+ * expected services.
49
+ */
50
+ export var RobotConnectivity;
51
+ (function (RobotConnectivity) {
52
+ /** Every expected service reports connected. */
53
+ RobotConnectivity["ONLINE"] = "online";
54
+ /** Some, but not all, expected services report connected. */
55
+ RobotConnectivity["DEGRADED"] = "degraded";
56
+ /** No expected service reports connected. */
57
+ RobotConnectivity["OFFLINE"] = "offline";
58
+ })(RobotConnectivity || (RobotConnectivity = {}));
@@ -43,6 +43,44 @@ export declare class CallerService extends BaseStreamService<ICallerStream> {
43
43
  ack$: Observable<IRocosCallerMessageResponseAck>;
44
44
  cancel: () => Promise<void>;
45
45
  };
46
+ /** Invoke a long-running action (ROS 2 action-server semantics) and expose its lifecycle safely.
47
+ *
48
+ * Use this instead of `call` when the request is *accepted* (ack) long before it
49
+ * *completes* (result) — e.g. a navigation goal or a mission. The semantics are:
50
+ * fire the request exactly once, hold the underlying stream open after the ack,
51
+ * and tear it down only when the action itself completes/errors.
52
+ *
53
+ * This differs from `call` in one crucial way: `call` builds `ack$`/`result$` on a
54
+ * refcounted shared source, so awaiting `ack$` (dropping the subscriber count to
55
+ * zero) and *then* subscribing to `result$` re-issues the goal. `callAction` pins the
56
+ * source with a single SDK-owned subscription for the action's lifetime, so:
57
+ * - the request fires once and is never re-issued by subscriber churn,
58
+ * - `ack` is a Promise (inherently replayable — await it in any order),
59
+ * - `result$` replays the one-shot result, so a late or out-of-order subscriber
60
+ * still receives it.
61
+ *
62
+ * Lifecycle:
63
+ * - `ack` resolves with the first acknowledgement; rejects if the action
64
+ * errors (or completes) before any ack arrives.
65
+ * - `result$` emits the single result and completes when the action ends. Replayed,
66
+ * so subscription order relative to awaiting `ack` does not matter.
67
+ * - `return$` streams live feedback/return payloads (decoded as `T`). Not replayed —
68
+ * subscribe before the action emits feedback to avoid missing it.
69
+ * - `cancel` asks the server to cancel; the action then emits its result and closes.
70
+ * - `close` stops tracking the action locally *without* cancelling it on the robot,
71
+ * releasing the underlying stream. For teardown paths (e.g. UI unmount)
72
+ * where the action should keep running but the result is no longer needed.
73
+ *
74
+ * @see call
75
+ * @see callRaw
76
+ */
77
+ callAction<T = unknown>(params: ICallerCallParams): {
78
+ ack: Promise<IRocosCallerMessageResponseAck>;
79
+ result$: Observable<IRocosCallerMessageResponseResult>;
80
+ return$: Observable<T>;
81
+ cancel: () => Promise<void>;
82
+ close: () => void;
83
+ };
46
84
  protected createStream(): Promise<ICallerStream>;
47
85
  protected getStream(config: IStreamConfig): ICallerStream;
48
86
  }
@@ -1,5 +1,5 @@
1
1
  import { ResultStatus, RocosResponseLevel, } from '../models';
2
- import { from, lastValueFrom, map, mergeMap, share, switchMap, take, takeUntil, throwError } from 'rxjs';
2
+ import { ReplaySubject, firstValueFrom, from, lastValueFrom, map, mergeMap, share, switchMap, take, takeUntil, throwError, } from 'rxjs';
3
3
  import { catchError, filter } from 'rxjs/operators';
4
4
  import { getResponses, handleChunkedMessages } from '../helpers/callerMessageHelpers';
5
5
  import { BaseStreamService } from './BaseStreamService';
@@ -101,6 +101,62 @@ export class CallerService extends BaseStreamService {
101
101
  cancel,
102
102
  };
103
103
  }
104
+ /** Invoke a long-running action (ROS 2 action-server semantics) and expose its lifecycle safely.
105
+ *
106
+ * Use this instead of `call` when the request is *accepted* (ack) long before it
107
+ * *completes* (result) — e.g. a navigation goal or a mission. The semantics are:
108
+ * fire the request exactly once, hold the underlying stream open after the ack,
109
+ * and tear it down only when the action itself completes/errors.
110
+ *
111
+ * This differs from `call` in one crucial way: `call` builds `ack$`/`result$` on a
112
+ * refcounted shared source, so awaiting `ack$` (dropping the subscriber count to
113
+ * zero) and *then* subscribing to `result$` re-issues the goal. `callAction` pins the
114
+ * source with a single SDK-owned subscription for the action's lifetime, so:
115
+ * - the request fires once and is never re-issued by subscriber churn,
116
+ * - `ack` is a Promise (inherently replayable — await it in any order),
117
+ * - `result$` replays the one-shot result, so a late or out-of-order subscriber
118
+ * still receives it.
119
+ *
120
+ * Lifecycle:
121
+ * - `ack` resolves with the first acknowledgement; rejects if the action
122
+ * errors (or completes) before any ack arrives.
123
+ * - `result$` emits the single result and completes when the action ends. Replayed,
124
+ * so subscription order relative to awaiting `ack` does not matter.
125
+ * - `return$` streams live feedback/return payloads (decoded as `T`). Not replayed —
126
+ * subscribe before the action emits feedback to avoid missing it.
127
+ * - `cancel` asks the server to cancel; the action then emits its result and closes.
128
+ * - `close` stops tracking the action locally *without* cancelling it on the robot,
129
+ * releasing the underlying stream. For teardown paths (e.g. UI unmount)
130
+ * where the action should keep running but the result is no longer needed.
131
+ *
132
+ * @see call
133
+ * @see callRaw
134
+ */
135
+ callAction(params) {
136
+ const stream = this.call(params);
137
+ // Replay the one-shot result so subscription order never matters and a late
138
+ // subscriber still receives it.
139
+ const result = new ReplaySubject(1);
140
+ // One SDK-owned subscription pins the shared source alive for the whole action.
141
+ // It fires the request once (first subscriber) and forwards the result into the
142
+ // replay subject, completing/erroring it when the action ends. Because this
143
+ // subscription outlives any `firstValueFrom(ack)` teardown, subscriber churn can
144
+ // never reset the source and re-issue the goal.
145
+ const pin = stream.result$.subscribe(result);
146
+ // `ack` rejects if the action errors or completes before any ack arrives. Since
147
+ // callAction is meant to be consumed via result$/return$ too, a caller may never
148
+ // touch `ack` — without a handler that rejection would surface as an unhandled
149
+ // promise rejection. Awaiting `action.ack` still rejects for callers who do care.
150
+ const ack = firstValueFrom(stream.ack$);
151
+ ack.catch(() => { });
152
+ return {
153
+ ack,
154
+ result$: result.asObservable(),
155
+ return$: stream.return$,
156
+ cancel: stream.cancel,
157
+ close: () => pin.unsubscribe(),
158
+ };
159
+ }
104
160
  async createStream() {
105
161
  return (await this.createStreamFromConfig(IDENTIFIER_NAME_CALLER, {
106
162
  url: this.config.url,
@@ -1,5 +1,5 @@
1
+ import { AddPanoramaRequest, AddPanoramaResponse, CreateObservation, Observation } from '../models/maps/Panorama';
1
2
  import { Asset, IBaseService, IRocosSDKConfig, Map, MapContent, RocosError } from '../models';
2
- import { CreateObservation, Observation } from '../models/maps/Panorama';
3
3
  import { BaseServiceAbstract } from './BaseServiceAbstract';
4
4
  /**
5
5
  * Maps service for managing robot maps in the cloud and on robots
@@ -202,6 +202,25 @@ export declare class MapService extends BaseServiceAbstract implements IBaseServ
202
202
  * @returns A list of assets
203
203
  */
204
204
  getAssetsKeys(projectId: string): Promise<string[]>;
205
+ /**
206
+ * Adds a panorama to the project's dronedeploy map (and optionally other named maps).
207
+ *
208
+ * The dronedeploy map is always written. To also write the panorama into additional maps,
209
+ * pass their ids in `body.map` (single string or array). Each named map must already exist —
210
+ * unknown ids reject the whole call with 400. Entries are deduplicated against dronedeploy
211
+ * and each other.
212
+ *
213
+ * Two server-side conveniences:
214
+ * - `body.transform.id` may be left blank ('') to have the server generate a UUID. The
215
+ * created id is returned in the response so the caller can subsequently get/delete it.
216
+ * - `body.transform.parent` is auto-created as a FRAME node when it doesn't already exist
217
+ * anywhere in the project; no separate "create parent frame" call is required.
218
+ *
219
+ * @param projectId The ID of the project the panorama belongs to.
220
+ * @param body Panorama transform + data, with an optional `map` selector.
221
+ * @returns The panorama node id that was created (echoed when supplied, generated when blank).
222
+ */
223
+ addPanorama(projectId: string, body: AddPanoramaRequest): Promise<AddPanoramaResponse>;
205
224
  /**
206
225
  * Deletes a panorama by panoramaID.
207
226
  *
@@ -1,4 +1,4 @@
1
- import { API_GRAPHS_MAPS_COPY_URL, API_GRAPHS_MAPS_DEPLOYED_URL, API_GRAPHS_MAPS_DEPLOY_URL, API_GRAPHS_MAPS_GEOJSON_URL, API_GRAPHS_MAPS_MERGE_URL, API_GRAPHS_MAPS_NEW_URL, API_GRAPHS_MAPS_URL, API_GRAPHS_MAP_CONTENT_URL, API_GRAPHS_MAP_ID_URL, API_GRAPHS_MAP_METADATA_URL, API_GRAPHS_OBSERVATIONS_URL, API_GRAPHS_OBSERVATION_KEYS_URL, API_GRAPHS_PANORAMA, API_GRAPHS_PANORAMA_OBSERVATIONS_URL, } from '../constants/api';
1
+ import { API_GRAPHS_MAPS_COPY_URL, API_GRAPHS_MAPS_DEPLOYED_URL, API_GRAPHS_MAPS_DEPLOY_URL, API_GRAPHS_MAPS_GEOJSON_URL, API_GRAPHS_MAPS_MERGE_URL, API_GRAPHS_MAPS_NEW_URL, API_GRAPHS_MAPS_URL, API_GRAPHS_MAP_CONTENT_URL, API_GRAPHS_MAP_ID_URL, API_GRAPHS_MAP_METADATA_URL, API_GRAPHS_OBSERVATIONS_URL, API_GRAPHS_OBSERVATION_KEYS_URL, API_GRAPHS_PANORAMA, API_GRAPHS_PANORAMAS_URL, API_GRAPHS_PANORAMA_OBSERVATIONS_URL, } from '../constants/api';
2
2
  import { RocosError, errorCodes } from '../models';
3
3
  import { BaseServiceAbstract } from './BaseServiceAbstract';
4
4
  import { RocosLogger } from '../logger/RocosLogger';
@@ -279,6 +279,27 @@ export class MapService extends BaseServiceAbstract {
279
279
  getAssetsKeys(projectId) {
280
280
  return this.callGet(formatServiceUrl(API_GRAPHS_OBSERVATION_KEYS_URL, { url: this.config.url, projectId }, this.config.insecure), 'Failed to get asset keys.');
281
281
  }
282
+ /**
283
+ * Adds a panorama to the project's dronedeploy map (and optionally other named maps).
284
+ *
285
+ * The dronedeploy map is always written. To also write the panorama into additional maps,
286
+ * pass their ids in `body.map` (single string or array). Each named map must already exist —
287
+ * unknown ids reject the whole call with 400. Entries are deduplicated against dronedeploy
288
+ * and each other.
289
+ *
290
+ * Two server-side conveniences:
291
+ * - `body.transform.id` may be left blank ('') to have the server generate a UUID. The
292
+ * created id is returned in the response so the caller can subsequently get/delete it.
293
+ * - `body.transform.parent` is auto-created as a FRAME node when it doesn't already exist
294
+ * anywhere in the project; no separate "create parent frame" call is required.
295
+ *
296
+ * @param projectId The ID of the project the panorama belongs to.
297
+ * @param body Panorama transform + data, with an optional `map` selector.
298
+ * @returns The panorama node id that was created (echoed when supplied, generated when blank).
299
+ */
300
+ addPanorama(projectId, body) {
301
+ return this.callPut(formatServiceUrl(API_GRAPHS_PANORAMAS_URL, { url: this.config.url, projectId }, this.config.insecure), body, 'Failed to add panorama.');
302
+ }
282
303
  /**
283
304
  * Deletes a panorama by panoramaID.
284
305
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dronedeploy/rocos-js-sdk",
3
- "version": "3.1.5",
3
+ "version": "3.1.7",
4
4
  "description": "Javascript SDK for rocos",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",