@dronedeploy/rocos-js-sdk 3.1.8 → 4.1.0

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
@@ -19,6 +19,11 @@ yarn add @dronedeploy/rocos-js-sdk rxjs@^7
19
19
 
20
20
  ## What's new
21
21
 
22
+ ### 4.0.0
23
+
24
+ * **BREAKING:** The default telemetry `transport` is now `'connect'` (the Connect protocol) instead of `'grpc-web'`. Consumers that do not set `transport` explicitly will switch to Connect automatically. If your backend or proxy only supports gRPC-web, restore the previous behaviour with `transport: 'grpc-web'`.
25
+ * The `'grpc-web'` telemetry transport is deprecated and will be removed in a future release. Selecting it now logs a one-time deprecation warning.
26
+
22
27
  ### 3.1.2
23
28
 
24
29
  * Use the optional `fetch` implementation for the gRPC-web transport too, so a custom `fetch` can be supplied consistently across transports.
@@ -3,7 +3,7 @@ import { TelemetryAckStatus, TelemetryQueryRequest, TelemetryRequest } from '../
3
3
  import { TelemetryStreamAbstract } from './TelemetryStreamAbstract';
4
4
  /**
5
5
  * Connect-protocol telemetry receive stream. Mirrors TelemetryStream (grpc-web) but uses
6
- * @connectrpc/connect. Selected when config.transport === 'connect'.
6
+ * @connectrpc/connect. The default transport, selected unless config.transport === 'grpc-web'.
7
7
  *
8
8
  * The shared TelemetryStreamAbstract is typed with the protobuf-ts message types, while the
9
9
  * Connect client uses @bufbuild/protobuf types. Both serialise to identical protobuf wire
@@ -11,7 +11,7 @@ const TelemetryStreamAbstract_1 = require("./TelemetryStreamAbstract");
11
11
  const connect_web_1 = require("@connectrpc/connect-web");
12
12
  /**
13
13
  * Connect-protocol telemetry receive stream. Mirrors TelemetryStream (grpc-web) but uses
14
- * @connectrpc/connect. Selected when config.transport === 'connect'.
14
+ * @connectrpc/connect. The default transport, selected unless config.transport === 'grpc-web'.
15
15
  *
16
16
  * The shared TelemetryStreamAbstract is typed with the protobuf-ts message types, while the
17
17
  * Connect client uses @bufbuild/protobuf types. Both serialise to identical protobuf wire
@@ -128,6 +128,12 @@ export declare const API_GRAPHS_MAPS_MERGE_URL = "https://{url}/graphs/projects/
128
128
  export declare const API_GRAPHS_MAP_ID_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}";
129
129
  export declare const API_GRAPHS_MAP_CONTENT_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/content";
130
130
  export declare const API_GRAPHS_MAP_METADATA_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/metadata";
131
+ export declare const API_GRAPHS_MAP_NODES_ADD_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add";
132
+ export declare const API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add/transformable";
133
+ export declare const API_GRAPHS_MAP_NODE_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/{nodeId}";
134
+ export declare const API_GRAPHS_MAP_EDGES_ADD_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add";
135
+ export declare const API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add/transform";
136
+ export declare const API_GRAPHS_MAP_EDGE_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/{edgeId}";
131
137
  export declare const API_GRAPHS_MAPS_COPY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy";
132
138
  export declare const API_GRAPHS_MAPS_DEPLOY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy";
133
139
  export declare const API_GRAPHS_MAPS_GEOJSON_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson";
@@ -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_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;
5
+ 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_EDGE_URL = exports.API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL = exports.API_GRAPHS_MAP_EDGES_ADD_URL = exports.API_GRAPHS_MAP_NODE_URL = exports.API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL = exports.API_GRAPHS_MAP_NODES_ADD_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 = 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 = 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';
@@ -134,6 +134,12 @@ exports.API_GRAPHS_MAPS_MERGE_URL = 'https://{url}/graphs/projects/{projectId}/m
134
134
  exports.API_GRAPHS_MAP_ID_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}';
135
135
  exports.API_GRAPHS_MAP_CONTENT_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/content';
136
136
  exports.API_GRAPHS_MAP_METADATA_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/metadata';
137
+ exports.API_GRAPHS_MAP_NODES_ADD_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add';
138
+ exports.API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add/transformable';
139
+ exports.API_GRAPHS_MAP_NODE_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/{nodeId}';
140
+ exports.API_GRAPHS_MAP_EDGES_ADD_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add';
141
+ exports.API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add/transform';
142
+ exports.API_GRAPHS_MAP_EDGE_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/{edgeId}';
137
143
  exports.API_GRAPHS_MAPS_COPY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy';
138
144
  exports.API_GRAPHS_MAPS_DEPLOY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy';
139
145
  exports.API_GRAPHS_MAPS_GEOJSON_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson';
@@ -1,5 +1,5 @@
1
1
  import { IStreamOptions } from './IStreamOptions';
2
- export type TelemetryTransport = 'grpc-web' | 'connect';
2
+ export type TelemetryTransport = 'connect' | 'grpc-web';
3
3
  export interface IStreamConfig {
4
4
  url: string;
5
5
  token: string;
@@ -49,6 +49,8 @@ export * from './IWidget';
49
49
  export * from './IWidgetLineGroup';
50
50
  export * from './maps/Map';
51
51
  export * from './maps/MapContent';
52
+ export * from './maps/MapEdge';
53
+ export * from './maps/MapNode';
52
54
  export * from './maps/Panorama';
53
55
  export * from './message';
54
56
  export * from './params/ICallerParams';
@@ -65,6 +65,8 @@ __exportStar(require("./IWidget"), exports);
65
65
  __exportStar(require("./IWidgetLineGroup"), exports);
66
66
  __exportStar(require("./maps/Map"), exports);
67
67
  __exportStar(require("./maps/MapContent"), exports);
68
+ __exportStar(require("./maps/MapEdge"), exports);
69
+ __exportStar(require("./maps/MapNode"), exports);
68
70
  __exportStar(require("./maps/Panorama"), exports);
69
71
  __exportStar(require("./message"), exports);
70
72
  __exportStar(require("./params/ICallerParams"), exports);
@@ -0,0 +1,47 @@
1
+ import { Quaternion, Vector3 } from '../graph';
2
+ /**
3
+ * Body of `POST /graphs/projects/{projectId}/maps/{mapId}/edges/add`. Adds a single edge
4
+ * between two existing nodes in the map. `id` is optional — when omitted the server derives
5
+ * it from `(from, to, type)`.
6
+ *
7
+ * Create-only: a colliding edge id in the target map is rejected with 409 rather than being
8
+ * upserted. Reserved edge types (`ALIAS`, `DEPLOYED`) and edges touching server-managed
9
+ * nodes are refused with 400, and both endpoint nodes must already exist (400 otherwise).
10
+ *
11
+ * A `TRANSFORM` edge may be added through this endpoint, but it must carry a valid 16-element
12
+ * row-major matrix under `data.TransformMatrix`; use {@link AddTransformEdgeRequest} /
13
+ * `MapService.addTransformEdge` to have the SDK build that matrix from a rotation + position.
14
+ */
15
+ export interface AddEdgeRequest {
16
+ from: string;
17
+ to: string;
18
+ type: string;
19
+ id?: string;
20
+ data?: Record<string, unknown>;
21
+ }
22
+ /**
23
+ * Caller-facing body for `POST /graphs/projects/{projectId}/maps/{mapId}/edges/add/transform`.
24
+ * Adds a `TRANSFORM` edge from `from` to `to`, positioning `to` relative to `from` by the
25
+ * supplied rotation + position. `id` is optional (derived from `(from, to, TRANSFORM)` when
26
+ * omitted). The `rot`/`pos` naming matches the panorama and node transforms.
27
+ *
28
+ * Wire-shape note: the server receives the transform as `{ rotation, translation }` nested
29
+ * under `transform`. `MapService.addTransformEdge` marshals `rot`/`pos` onto that shape
30
+ * before POSTing; callers only ever see the `rot`/`pos` form.
31
+ */
32
+ export interface AddTransformEdgeRequest {
33
+ from: string;
34
+ to: string;
35
+ id?: string;
36
+ transform: {
37
+ rot: Quaternion;
38
+ pos: Vector3;
39
+ };
40
+ }
41
+ /**
42
+ * Body returned by both edge-add endpoints. `id` echoes the value the caller supplied, or
43
+ * the id the server derived from `(from, to, type)` when none was given.
44
+ */
45
+ export interface AddEdgeResponse {
46
+ id: string;
47
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,48 @@
1
+ import { Quaternion, Vector3 } from '../graph';
2
+ /**
3
+ * A rigid-body affine transform (rotation + position) expressed relative to a named parent
4
+ * frame. The parent is part of the type so an `AffineTransform` value is well-formed on its
5
+ * own — a rotation+position without a parent frame is meaningless because there's nothing to
6
+ * measure it against. Field naming matches the {@link Panorama} transform (`pos`/`rot`).
7
+ */
8
+ export interface AffineTransform {
9
+ /** Id of the frame node the transform is measured relative to. */
10
+ parent: string;
11
+ rot: Quaternion;
12
+ pos: Vector3;
13
+ }
14
+ /**
15
+ * Body of `POST /graphs/projects/{projectId}/maps/{mapId}/nodes/add`. Adds a single node to
16
+ * an existing map without a parent-transform edge — the node lands "loose" in the map's
17
+ * graph. Use {@link AddTransformableNodeRequest} when you also need to position the node
18
+ * under an existing frame.
19
+ *
20
+ * Create-only: a duplicate `id` in the target map is rejected with 409 rather than being
21
+ * upserted. Server-managed types (`SUMMARY`, `CALLSIGN`, `GeoScene`, `MAP_INFO`) are refused
22
+ * with 400.
23
+ */
24
+ export interface AddNodeRequest {
25
+ id: string;
26
+ type: string;
27
+ data?: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * Body of `POST /graphs/projects/{projectId}/maps/{mapId}/nodes/add/transformable`. Same
31
+ * as {@link AddNodeRequest} plus an {@link AffineTransform} that positions the new node
32
+ * under an existing frame in the map via a `TRANSFORM` edge.
33
+ *
34
+ * The frame node must already exist in the target map — a missing frame is rejected with
35
+ * 400, and a frame that disappears between the pre-check and the write returns 409.
36
+ *
37
+ * Note on wire format: the server currently receives `frame` and `transform` as sibling
38
+ * fields, with `transform.translation` instead of `pos`. `MapService.addTransformableNode`
39
+ * translates this shape onto the wire before POSTing; callers only ever see the
40
+ * {@link AffineTransform} form.
41
+ */
42
+ export interface AddTransformableNodeRequest extends AddNodeRequest {
43
+ transform: AffineTransform;
44
+ }
45
+ /** Body returned by both add endpoints. `id` echoes the value the caller supplied. */
46
+ export interface AddNodeResponse {
47
+ id: string;
48
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,5 @@
1
+ import { AddEdgeRequest, AddEdgeResponse, AddTransformEdgeRequest } from '../models/maps/MapEdge';
2
+ import { AddNodeRequest, AddNodeResponse, AddTransformableNodeRequest } from '../models/maps/MapNode';
1
3
  import { AddPanoramaRequest, AddPanoramaResponse, CreateObservation, Observation } from '../models/maps/Panorama';
2
4
  import { Asset, IBaseService, IRocosSDKConfig, Map, MapContent, RocosError } from '../models';
3
5
  import { BaseServiceAbstract } from './BaseServiceAbstract';
@@ -229,4 +231,107 @@ export declare class MapService extends BaseServiceAbstract implements IBaseServ
229
231
  * @returns A Promise.
230
232
  */
231
233
  deletePanorama(projectId: string, panoramaId: string): Promise<void>;
234
+ /**
235
+ * Add a single node to an existing map. A low-impact, targeted alternative to replacing the
236
+ * whole map via {@link create} — same access surface (permitted on the reserved dronedeploy
237
+ * map and on normal maps; the environment map remains off-limits).
238
+ *
239
+ * Create-only: a duplicate id in the target map is rejected with 409 rather than being
240
+ * silently upserted, to keep the blast radius small on the shared dronedeploy map.
241
+ * Server-managed types (`SUMMARY`, `CALLSIGN`, `GeoScene`, `MAP_INFO`) are refused with
242
+ * 400. Adding to a map that doesn't exist returns 404.
243
+ *
244
+ * @param projectId The ID of the project the map belongs to.
245
+ * @param mapId The ID of the map to add the node to.
246
+ * @param body The node to add.
247
+ * @returns The id of the created node (echoes `body.id`).
248
+ */
249
+ addNode(projectId: string, mapId: string, body: AddNodeRequest): Promise<AddNodeResponse>;
250
+ /**
251
+ * Add a single node **and** a `TRANSFORM` edge that positions it under an existing frame
252
+ * node in the same map, by the supplied rotation + position. Same access rules and
253
+ * create-only semantics as {@link addNode}.
254
+ *
255
+ * The parent frame node (`body.transform.parent`) must already exist in the target map —
256
+ * a missing frame is rejected with 400, and a frame that vanishes between the pre-check
257
+ * and the write returns 409 (the transaction rolls back so no orphan node is created).
258
+ *
259
+ * Wire-shape note: the server currently receives `frame` as a top-level field alongside
260
+ * `transform`, and expects the position under the wire name `translation`. This method
261
+ * marshals the caller-facing {@link AddTransformableNodeRequest} (which carries `parent`
262
+ * inline in `transform` and uses `pos`/`rot` to match the panorama transform) onto that
263
+ * shape before POSTing.
264
+ *
265
+ * @param projectId The ID of the project the map belongs to.
266
+ * @param mapId The ID of the map to add the node to.
267
+ * @param body The node to add plus the transform that positions it under a parent frame.
268
+ * @returns The id of the created node (echoes `body.id`).
269
+ */
270
+ addTransformableNode(projectId: string, mapId: string, body: AddTransformableNodeRequest): Promise<AddNodeResponse>;
271
+ /**
272
+ * Delete a single node (and any edges attached to it) from a map. Idempotent — a missing
273
+ * node still returns success. Refuses server-managed types (`SUMMARY`, `CALLSIGN`,
274
+ * `GeoScene`, `MAP_INFO`) with 400.
275
+ *
276
+ * Access rules differ from the add endpoints because deleting has a larger blast radius:
277
+ * the environment map is always off-limits; the dronedeploy map is deletable only by
278
+ * admin users (server enforces via 401/403); normal maps are deletable by any caller with
279
+ * project access.
280
+ *
281
+ * @param projectId The ID of the project the map belongs to.
282
+ * @param mapId The ID of the map to delete the node from.
283
+ * @param nodeId The ID of the node to delete.
284
+ */
285
+ deleteNode(projectId: string, mapId: string, nodeId: string): Promise<void>;
286
+ /**
287
+ * Add a single edge between two existing nodes in a map. The edge-side counterpart of
288
+ * {@link addNode}: a low-impact, targeted alternative to replacing the whole map — same
289
+ * access surface (permitted on the reserved dronedeploy map and on normal maps; the
290
+ * environment map remains off-limits).
291
+ *
292
+ * Create-only: a colliding edge id is rejected with 409 rather than upserted. Reserved
293
+ * edge types (`ALIAS`, `DEPLOYED`) and edges touching server-managed nodes are refused
294
+ * with 400, both endpoint nodes must already exist (400 otherwise), and a `TRANSFORM`
295
+ * edge must carry a valid `data.TransformMatrix` (use {@link addTransformEdge} to build
296
+ * one from a rotation + position). Adding to a map that doesn't exist returns 404.
297
+ *
298
+ * @param projectId The ID of the project the map belongs to.
299
+ * @param mapId The ID of the map to add the edge to.
300
+ * @param body The edge to add. `id` is optional; when omitted the server derives it.
301
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
302
+ */
303
+ addEdge(projectId: string, mapId: string, body: AddEdgeRequest): Promise<AddEdgeResponse>;
304
+ /**
305
+ * Add a single `TRANSFORM` edge from one existing node to another, positioning the `to`
306
+ * node relative to the `from` node by the supplied rotation + position. A specialisation
307
+ * of {@link addEdge} with the type fixed to `TRANSFORM` and the matrix built server-side;
308
+ * same access rules and create-only semantics.
309
+ *
310
+ * Both endpoint nodes must already exist in the target map (400 otherwise).
311
+ *
312
+ * Wire-shape note: the server receives the transform as `{ rotation, translation }` nested
313
+ * under `transform`. This method marshals the caller-facing `rot`/`pos` (matching the
314
+ * panorama/node transform naming) onto that shape before POSTing.
315
+ *
316
+ * @param projectId The ID of the project the map belongs to.
317
+ * @param mapId The ID of the map to add the edge to.
318
+ * @param body The transform edge to add. `id` is optional; when omitted the server derives it.
319
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
320
+ */
321
+ addTransformEdge(projectId: string, mapId: string, body: AddTransformEdgeRequest): Promise<AddEdgeResponse>;
322
+ /**
323
+ * Delete a single edge by id from a map. Idempotent — a missing edge still returns
324
+ * success. Reserved/server-managed edge types and edges touching server-managed nodes are
325
+ * refused with 400.
326
+ *
327
+ * Access rules match {@link deleteNode} (deleting has a larger blast radius than adding):
328
+ * the environment map is always off-limits; the dronedeploy map is deletable only by admin
329
+ * users (server enforces via 401/403); normal maps are deletable by any caller with project
330
+ * access.
331
+ *
332
+ * @param projectId The ID of the project the map belongs to.
333
+ * @param mapId The ID of the map to delete the edge from.
334
+ * @param edgeId The ID of the edge to delete.
335
+ */
336
+ deleteEdge(projectId: string, mapId: string, edgeId: string): Promise<void>;
232
337
  }
@@ -313,5 +313,146 @@ class MapService extends BaseServiceAbstract_1.BaseServiceAbstract {
313
313
  deletePanorama(projectId, panoramaId) {
314
314
  return this.callDelete((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_PANORAMA, { url: this.config.url, projectId, panoramaId }, this.config.insecure), 'Failed to delete panorama.');
315
315
  }
316
+ /**
317
+ * Add a single node to an existing map. A low-impact, targeted alternative to replacing the
318
+ * whole map via {@link create} — same access surface (permitted on the reserved dronedeploy
319
+ * map and on normal maps; the environment map remains off-limits).
320
+ *
321
+ * Create-only: a duplicate id in the target map is rejected with 409 rather than being
322
+ * silently upserted, to keep the blast radius small on the shared dronedeploy map.
323
+ * Server-managed types (`SUMMARY`, `CALLSIGN`, `GeoScene`, `MAP_INFO`) are refused with
324
+ * 400. Adding to a map that doesn't exist returns 404.
325
+ *
326
+ * @param projectId The ID of the project the map belongs to.
327
+ * @param mapId The ID of the map to add the node to.
328
+ * @param body The node to add.
329
+ * @returns The id of the created node (echoes `body.id`).
330
+ */
331
+ addNode(projectId, mapId, body) {
332
+ return this.callPost((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_MAP_NODES_ADD_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), body, 'Failed to add node.');
333
+ }
334
+ /**
335
+ * Add a single node **and** a `TRANSFORM` edge that positions it under an existing frame
336
+ * node in the same map, by the supplied rotation + position. Same access rules and
337
+ * create-only semantics as {@link addNode}.
338
+ *
339
+ * The parent frame node (`body.transform.parent`) must already exist in the target map —
340
+ * a missing frame is rejected with 400, and a frame that vanishes between the pre-check
341
+ * and the write returns 409 (the transaction rolls back so no orphan node is created).
342
+ *
343
+ * Wire-shape note: the server currently receives `frame` as a top-level field alongside
344
+ * `transform`, and expects the position under the wire name `translation`. This method
345
+ * marshals the caller-facing {@link AddTransformableNodeRequest} (which carries `parent`
346
+ * inline in `transform` and uses `pos`/`rot` to match the panorama transform) onto that
347
+ * shape before POSTing.
348
+ *
349
+ * @param projectId The ID of the project the map belongs to.
350
+ * @param mapId The ID of the map to add the node to.
351
+ * @param body The node to add plus the transform that positions it under a parent frame.
352
+ * @returns The id of the created node (echoes `body.id`).
353
+ */
354
+ addTransformableNode(projectId, mapId, body) {
355
+ // Translate the caller-facing shape (parent inline in `transform`, `pos`/`rot`) onto the
356
+ // server's wire shape (`frame` at the top level, `translation`/`rotation` inside
357
+ // `transform`). Rationale for the divergence: the SDK type keeps `AffineTransform` well
358
+ // formed in isolation and mirrors the `Panorama.transform` naming (`pos`/`rot`); the
359
+ // server predates this convention and hasn't been migrated yet.
360
+ const wireBody = {
361
+ id: body.id,
362
+ type: body.type,
363
+ data: body.data,
364
+ frame: body.transform.parent,
365
+ transform: {
366
+ rotation: body.transform.rot,
367
+ translation: body.transform.pos,
368
+ },
369
+ };
370
+ return this.callPost((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), wireBody, 'Failed to add transformable node.');
371
+ }
372
+ /**
373
+ * Delete a single node (and any edges attached to it) from a map. Idempotent — a missing
374
+ * node still returns success. Refuses server-managed types (`SUMMARY`, `CALLSIGN`,
375
+ * `GeoScene`, `MAP_INFO`) with 400.
376
+ *
377
+ * Access rules differ from the add endpoints because deleting has a larger blast radius:
378
+ * the environment map is always off-limits; the dronedeploy map is deletable only by
379
+ * admin users (server enforces via 401/403); normal maps are deletable by any caller with
380
+ * project access.
381
+ *
382
+ * @param projectId The ID of the project the map belongs to.
383
+ * @param mapId The ID of the map to delete the node from.
384
+ * @param nodeId The ID of the node to delete.
385
+ */
386
+ deleteNode(projectId, mapId, nodeId) {
387
+ return this.callDelete((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_MAP_NODE_URL, { url: this.config.url, projectId, mapId, nodeId }, this.config.insecure), 'Failed to delete node.');
388
+ }
389
+ /**
390
+ * Add a single edge between two existing nodes in a map. The edge-side counterpart of
391
+ * {@link addNode}: a low-impact, targeted alternative to replacing the whole map — same
392
+ * access surface (permitted on the reserved dronedeploy map and on normal maps; the
393
+ * environment map remains off-limits).
394
+ *
395
+ * Create-only: a colliding edge id is rejected with 409 rather than upserted. Reserved
396
+ * edge types (`ALIAS`, `DEPLOYED`) and edges touching server-managed nodes are refused
397
+ * with 400, both endpoint nodes must already exist (400 otherwise), and a `TRANSFORM`
398
+ * edge must carry a valid `data.TransformMatrix` (use {@link addTransformEdge} to build
399
+ * one from a rotation + position). Adding to a map that doesn't exist returns 404.
400
+ *
401
+ * @param projectId The ID of the project the map belongs to.
402
+ * @param mapId The ID of the map to add the edge to.
403
+ * @param body The edge to add. `id` is optional; when omitted the server derives it.
404
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
405
+ */
406
+ addEdge(projectId, mapId, body) {
407
+ return this.callPost((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_MAP_EDGES_ADD_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), body, 'Failed to add edge.');
408
+ }
409
+ /**
410
+ * Add a single `TRANSFORM` edge from one existing node to another, positioning the `to`
411
+ * node relative to the `from` node by the supplied rotation + position. A specialisation
412
+ * of {@link addEdge} with the type fixed to `TRANSFORM` and the matrix built server-side;
413
+ * same access rules and create-only semantics.
414
+ *
415
+ * Both endpoint nodes must already exist in the target map (400 otherwise).
416
+ *
417
+ * Wire-shape note: the server receives the transform as `{ rotation, translation }` nested
418
+ * under `transform`. This method marshals the caller-facing `rot`/`pos` (matching the
419
+ * panorama/node transform naming) onto that shape before POSTing.
420
+ *
421
+ * @param projectId The ID of the project the map belongs to.
422
+ * @param mapId The ID of the map to add the edge to.
423
+ * @param body The transform edge to add. `id` is optional; when omitted the server derives it.
424
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
425
+ */
426
+ addTransformEdge(projectId, mapId, body) {
427
+ // Translate the caller-facing `rot`/`pos` onto the server's wire shape
428
+ // (`transform.rotation`/`transform.translation`), mirroring addTransformableNode.
429
+ const wireBody = {
430
+ id: body.id,
431
+ from: body.from,
432
+ to: body.to,
433
+ transform: {
434
+ rotation: body.transform.rot,
435
+ translation: body.transform.pos,
436
+ },
437
+ };
438
+ return this.callPost((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), wireBody, 'Failed to add transform edge.');
439
+ }
440
+ /**
441
+ * Delete a single edge by id from a map. Idempotent — a missing edge still returns
442
+ * success. Reserved/server-managed edge types and edges touching server-managed nodes are
443
+ * refused with 400.
444
+ *
445
+ * Access rules match {@link deleteNode} (deleting has a larger blast radius than adding):
446
+ * the environment map is always off-limits; the dronedeploy map is deletable only by admin
447
+ * users (server enforces via 401/403); normal maps are deletable by any caller with project
448
+ * access.
449
+ *
450
+ * @param projectId The ID of the project the map belongs to.
451
+ * @param mapId The ID of the map to delete the edge from.
452
+ * @param edgeId The ID of the edge to delete.
453
+ */
454
+ deleteEdge(projectId, mapId, edgeId) {
455
+ return this.callDelete((0, formatServiceUrl_1.formatServiceUrl)(api_1.API_GRAPHS_MAP_EDGE_URL, { url: this.config.url, projectId, mapId, edgeId }, this.config.insecure), 'Failed to delete edge.');
456
+ }
316
457
  }
317
458
  exports.MapService = MapService;
@@ -2,6 +2,7 @@ import { Observable } from 'rxjs';
2
2
  import { CallsignStatus, IRocosSDKConfig, IRocosTelemetryMessage, IStreamStatusMessage, ITelemetryStream, ITelemetryStreamConfig, ITelemetrySubscriptionParams, ITelemetrySubscriptions, TelemetryMonitorStatus } from '../models';
3
3
  import { BaseStreamService } from './BaseStreamService';
4
4
  export declare class TelemetryService extends BaseStreamService<ITelemetryStream, ITelemetryStreamConfig> {
5
+ private static grpcWebDeprecationWarned;
5
6
  private statusSubscription;
6
7
  private changeStream$;
7
8
  private streamStatusSubject$;
@@ -177,10 +177,16 @@ class TelemetryService extends BaseStreamService_1.BaseStreamService {
177
177
  return newStream.stream;
178
178
  }
179
179
  getStream(config) {
180
- if (config.transport === 'connect') {
181
- return new TelemetryStreamConnect_1.TelemetryStreamConnect(config);
180
+ if (config.transport === 'grpc-web') {
181
+ if (!TelemetryService.grpcWebDeprecationWarned) {
182
+ TelemetryService.grpcWebDeprecationWarned = true;
183
+ this.logger.warn('The grpc-web telemetry transport is deprecated and will be removed in a future release. ' +
184
+ 'Switch to the Connect protocol by setting transport to "connect" (now the default).');
185
+ }
186
+ return new TelemetryStream_1.TelemetryStream(config);
182
187
  }
183
- return new TelemetryStream_1.TelemetryStream(config);
188
+ return new TelemetryStreamConnect_1.TelemetryStreamConnect(config);
184
189
  }
185
190
  }
186
191
  exports.TelemetryService = TelemetryService;
192
+ TelemetryService.grpcWebDeprecationWarned = false;
@@ -3,7 +3,7 @@ import { TelemetryAckStatus, TelemetryQueryRequest, TelemetryRequest } from '../
3
3
  import { TelemetryStreamAbstract } from './TelemetryStreamAbstract';
4
4
  /**
5
5
  * Connect-protocol telemetry receive stream. Mirrors TelemetryStream (grpc-web) but uses
6
- * @connectrpc/connect. Selected when config.transport === 'connect'.
6
+ * @connectrpc/connect. The default transport, selected unless config.transport === 'grpc-web'.
7
7
  *
8
8
  * The shared TelemetryStreamAbstract is typed with the protobuf-ts message types, while the
9
9
  * Connect client uses @bufbuild/protobuf types. Both serialise to identical protobuf wire
@@ -8,7 +8,7 @@ import { TelemetryStreamAbstract } from './TelemetryStreamAbstract';
8
8
  import { createConnectTransport } from '@connectrpc/connect-web';
9
9
  /**
10
10
  * Connect-protocol telemetry receive stream. Mirrors TelemetryStream (grpc-web) but uses
11
- * @connectrpc/connect. Selected when config.transport === 'connect'.
11
+ * @connectrpc/connect. The default transport, selected unless config.transport === 'grpc-web'.
12
12
  *
13
13
  * The shared TelemetryStreamAbstract is typed with the protobuf-ts message types, while the
14
14
  * Connect client uses @bufbuild/protobuf types. Both serialise to identical protobuf wire
@@ -128,6 +128,12 @@ export declare const API_GRAPHS_MAPS_MERGE_URL = "https://{url}/graphs/projects/
128
128
  export declare const API_GRAPHS_MAP_ID_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}";
129
129
  export declare const API_GRAPHS_MAP_CONTENT_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/content";
130
130
  export declare const API_GRAPHS_MAP_METADATA_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/metadata";
131
+ export declare const API_GRAPHS_MAP_NODES_ADD_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add";
132
+ export declare const API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add/transformable";
133
+ export declare const API_GRAPHS_MAP_NODE_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/{nodeId}";
134
+ export declare const API_GRAPHS_MAP_EDGES_ADD_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add";
135
+ export declare const API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add/transform";
136
+ export declare const API_GRAPHS_MAP_EDGE_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/{edgeId}";
131
137
  export declare const API_GRAPHS_MAPS_COPY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy";
132
138
  export declare const API_GRAPHS_MAPS_DEPLOY_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy";
133
139
  export declare const API_GRAPHS_MAPS_GEOJSON_URL = "https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson";
@@ -128,6 +128,12 @@ export const API_GRAPHS_MAPS_MERGE_URL = 'https://{url}/graphs/projects/{project
128
128
  export const API_GRAPHS_MAP_ID_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}';
129
129
  export const API_GRAPHS_MAP_CONTENT_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/content';
130
130
  export const API_GRAPHS_MAP_METADATA_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/metadata';
131
+ export const API_GRAPHS_MAP_NODES_ADD_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add';
132
+ export const API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/add/transformable';
133
+ export const API_GRAPHS_MAP_NODE_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/nodes/{nodeId}';
134
+ export const API_GRAPHS_MAP_EDGES_ADD_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add';
135
+ export const API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/add/transform';
136
+ export const API_GRAPHS_MAP_EDGE_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/edges/{edgeId}';
131
137
  export const API_GRAPHS_MAPS_COPY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/copy';
132
138
  export const API_GRAPHS_MAPS_DEPLOY_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/deploy';
133
139
  export const API_GRAPHS_MAPS_GEOJSON_URL = 'https://{url}/graphs/projects/{projectId}/maps/{mapId}/geojson';
@@ -1,5 +1,5 @@
1
1
  import { IStreamOptions } from './IStreamOptions';
2
- export type TelemetryTransport = 'grpc-web' | 'connect';
2
+ export type TelemetryTransport = 'connect' | 'grpc-web';
3
3
  export interface IStreamConfig {
4
4
  url: string;
5
5
  token: string;
@@ -49,6 +49,8 @@ export * from './IWidget';
49
49
  export * from './IWidgetLineGroup';
50
50
  export * from './maps/Map';
51
51
  export * from './maps/MapContent';
52
+ export * from './maps/MapEdge';
53
+ export * from './maps/MapNode';
52
54
  export * from './maps/Panorama';
53
55
  export * from './message';
54
56
  export * from './params/ICallerParams';
@@ -49,6 +49,8 @@ export * from './IWidget';
49
49
  export * from './IWidgetLineGroup';
50
50
  export * from './maps/Map';
51
51
  export * from './maps/MapContent';
52
+ export * from './maps/MapEdge';
53
+ export * from './maps/MapNode';
52
54
  export * from './maps/Panorama';
53
55
  export * from './message';
54
56
  export * from './params/ICallerParams';
@@ -0,0 +1,47 @@
1
+ import { Quaternion, Vector3 } from '../graph';
2
+ /**
3
+ * Body of `POST /graphs/projects/{projectId}/maps/{mapId}/edges/add`. Adds a single edge
4
+ * between two existing nodes in the map. `id` is optional — when omitted the server derives
5
+ * it from `(from, to, type)`.
6
+ *
7
+ * Create-only: a colliding edge id in the target map is rejected with 409 rather than being
8
+ * upserted. Reserved edge types (`ALIAS`, `DEPLOYED`) and edges touching server-managed
9
+ * nodes are refused with 400, and both endpoint nodes must already exist (400 otherwise).
10
+ *
11
+ * A `TRANSFORM` edge may be added through this endpoint, but it must carry a valid 16-element
12
+ * row-major matrix under `data.TransformMatrix`; use {@link AddTransformEdgeRequest} /
13
+ * `MapService.addTransformEdge` to have the SDK build that matrix from a rotation + position.
14
+ */
15
+ export interface AddEdgeRequest {
16
+ from: string;
17
+ to: string;
18
+ type: string;
19
+ id?: string;
20
+ data?: Record<string, unknown>;
21
+ }
22
+ /**
23
+ * Caller-facing body for `POST /graphs/projects/{projectId}/maps/{mapId}/edges/add/transform`.
24
+ * Adds a `TRANSFORM` edge from `from` to `to`, positioning `to` relative to `from` by the
25
+ * supplied rotation + position. `id` is optional (derived from `(from, to, TRANSFORM)` when
26
+ * omitted). The `rot`/`pos` naming matches the panorama and node transforms.
27
+ *
28
+ * Wire-shape note: the server receives the transform as `{ rotation, translation }` nested
29
+ * under `transform`. `MapService.addTransformEdge` marshals `rot`/`pos` onto that shape
30
+ * before POSTing; callers only ever see the `rot`/`pos` form.
31
+ */
32
+ export interface AddTransformEdgeRequest {
33
+ from: string;
34
+ to: string;
35
+ id?: string;
36
+ transform: {
37
+ rot: Quaternion;
38
+ pos: Vector3;
39
+ };
40
+ }
41
+ /**
42
+ * Body returned by both edge-add endpoints. `id` echoes the value the caller supplied, or
43
+ * the id the server derived from `(from, to, type)` when none was given.
44
+ */
45
+ export interface AddEdgeResponse {
46
+ id: string;
47
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import { Quaternion, Vector3 } from '../graph';
2
+ /**
3
+ * A rigid-body affine transform (rotation + position) expressed relative to a named parent
4
+ * frame. The parent is part of the type so an `AffineTransform` value is well-formed on its
5
+ * own — a rotation+position without a parent frame is meaningless because there's nothing to
6
+ * measure it against. Field naming matches the {@link Panorama} transform (`pos`/`rot`).
7
+ */
8
+ export interface AffineTransform {
9
+ /** Id of the frame node the transform is measured relative to. */
10
+ parent: string;
11
+ rot: Quaternion;
12
+ pos: Vector3;
13
+ }
14
+ /**
15
+ * Body of `POST /graphs/projects/{projectId}/maps/{mapId}/nodes/add`. Adds a single node to
16
+ * an existing map without a parent-transform edge — the node lands "loose" in the map's
17
+ * graph. Use {@link AddTransformableNodeRequest} when you also need to position the node
18
+ * under an existing frame.
19
+ *
20
+ * Create-only: a duplicate `id` in the target map is rejected with 409 rather than being
21
+ * upserted. Server-managed types (`SUMMARY`, `CALLSIGN`, `GeoScene`, `MAP_INFO`) are refused
22
+ * with 400.
23
+ */
24
+ export interface AddNodeRequest {
25
+ id: string;
26
+ type: string;
27
+ data?: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * Body of `POST /graphs/projects/{projectId}/maps/{mapId}/nodes/add/transformable`. Same
31
+ * as {@link AddNodeRequest} plus an {@link AffineTransform} that positions the new node
32
+ * under an existing frame in the map via a `TRANSFORM` edge.
33
+ *
34
+ * The frame node must already exist in the target map — a missing frame is rejected with
35
+ * 400, and a frame that disappears between the pre-check and the write returns 409.
36
+ *
37
+ * Note on wire format: the server currently receives `frame` and `transform` as sibling
38
+ * fields, with `transform.translation` instead of `pos`. `MapService.addTransformableNode`
39
+ * translates this shape onto the wire before POSTing; callers only ever see the
40
+ * {@link AffineTransform} form.
41
+ */
42
+ export interface AddTransformableNodeRequest extends AddNodeRequest {
43
+ transform: AffineTransform;
44
+ }
45
+ /** Body returned by both add endpoints. `id` echoes the value the caller supplied. */
46
+ export interface AddNodeResponse {
47
+ id: string;
48
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,5 @@
1
+ import { AddEdgeRequest, AddEdgeResponse, AddTransformEdgeRequest } from '../models/maps/MapEdge';
2
+ import { AddNodeRequest, AddNodeResponse, AddTransformableNodeRequest } from '../models/maps/MapNode';
1
3
  import { AddPanoramaRequest, AddPanoramaResponse, CreateObservation, Observation } from '../models/maps/Panorama';
2
4
  import { Asset, IBaseService, IRocosSDKConfig, Map, MapContent, RocosError } from '../models';
3
5
  import { BaseServiceAbstract } from './BaseServiceAbstract';
@@ -229,4 +231,107 @@ export declare class MapService extends BaseServiceAbstract implements IBaseServ
229
231
  * @returns A Promise.
230
232
  */
231
233
  deletePanorama(projectId: string, panoramaId: string): Promise<void>;
234
+ /**
235
+ * Add a single node to an existing map. A low-impact, targeted alternative to replacing the
236
+ * whole map via {@link create} — same access surface (permitted on the reserved dronedeploy
237
+ * map and on normal maps; the environment map remains off-limits).
238
+ *
239
+ * Create-only: a duplicate id in the target map is rejected with 409 rather than being
240
+ * silently upserted, to keep the blast radius small on the shared dronedeploy map.
241
+ * Server-managed types (`SUMMARY`, `CALLSIGN`, `GeoScene`, `MAP_INFO`) are refused with
242
+ * 400. Adding to a map that doesn't exist returns 404.
243
+ *
244
+ * @param projectId The ID of the project the map belongs to.
245
+ * @param mapId The ID of the map to add the node to.
246
+ * @param body The node to add.
247
+ * @returns The id of the created node (echoes `body.id`).
248
+ */
249
+ addNode(projectId: string, mapId: string, body: AddNodeRequest): Promise<AddNodeResponse>;
250
+ /**
251
+ * Add a single node **and** a `TRANSFORM` edge that positions it under an existing frame
252
+ * node in the same map, by the supplied rotation + position. Same access rules and
253
+ * create-only semantics as {@link addNode}.
254
+ *
255
+ * The parent frame node (`body.transform.parent`) must already exist in the target map —
256
+ * a missing frame is rejected with 400, and a frame that vanishes between the pre-check
257
+ * and the write returns 409 (the transaction rolls back so no orphan node is created).
258
+ *
259
+ * Wire-shape note: the server currently receives `frame` as a top-level field alongside
260
+ * `transform`, and expects the position under the wire name `translation`. This method
261
+ * marshals the caller-facing {@link AddTransformableNodeRequest} (which carries `parent`
262
+ * inline in `transform` and uses `pos`/`rot` to match the panorama transform) onto that
263
+ * shape before POSTing.
264
+ *
265
+ * @param projectId The ID of the project the map belongs to.
266
+ * @param mapId The ID of the map to add the node to.
267
+ * @param body The node to add plus the transform that positions it under a parent frame.
268
+ * @returns The id of the created node (echoes `body.id`).
269
+ */
270
+ addTransformableNode(projectId: string, mapId: string, body: AddTransformableNodeRequest): Promise<AddNodeResponse>;
271
+ /**
272
+ * Delete a single node (and any edges attached to it) from a map. Idempotent — a missing
273
+ * node still returns success. Refuses server-managed types (`SUMMARY`, `CALLSIGN`,
274
+ * `GeoScene`, `MAP_INFO`) with 400.
275
+ *
276
+ * Access rules differ from the add endpoints because deleting has a larger blast radius:
277
+ * the environment map is always off-limits; the dronedeploy map is deletable only by
278
+ * admin users (server enforces via 401/403); normal maps are deletable by any caller with
279
+ * project access.
280
+ *
281
+ * @param projectId The ID of the project the map belongs to.
282
+ * @param mapId The ID of the map to delete the node from.
283
+ * @param nodeId The ID of the node to delete.
284
+ */
285
+ deleteNode(projectId: string, mapId: string, nodeId: string): Promise<void>;
286
+ /**
287
+ * Add a single edge between two existing nodes in a map. The edge-side counterpart of
288
+ * {@link addNode}: a low-impact, targeted alternative to replacing the whole map — same
289
+ * access surface (permitted on the reserved dronedeploy map and on normal maps; the
290
+ * environment map remains off-limits).
291
+ *
292
+ * Create-only: a colliding edge id is rejected with 409 rather than upserted. Reserved
293
+ * edge types (`ALIAS`, `DEPLOYED`) and edges touching server-managed nodes are refused
294
+ * with 400, both endpoint nodes must already exist (400 otherwise), and a `TRANSFORM`
295
+ * edge must carry a valid `data.TransformMatrix` (use {@link addTransformEdge} to build
296
+ * one from a rotation + position). Adding to a map that doesn't exist returns 404.
297
+ *
298
+ * @param projectId The ID of the project the map belongs to.
299
+ * @param mapId The ID of the map to add the edge to.
300
+ * @param body The edge to add. `id` is optional; when omitted the server derives it.
301
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
302
+ */
303
+ addEdge(projectId: string, mapId: string, body: AddEdgeRequest): Promise<AddEdgeResponse>;
304
+ /**
305
+ * Add a single `TRANSFORM` edge from one existing node to another, positioning the `to`
306
+ * node relative to the `from` node by the supplied rotation + position. A specialisation
307
+ * of {@link addEdge} with the type fixed to `TRANSFORM` and the matrix built server-side;
308
+ * same access rules and create-only semantics.
309
+ *
310
+ * Both endpoint nodes must already exist in the target map (400 otherwise).
311
+ *
312
+ * Wire-shape note: the server receives the transform as `{ rotation, translation }` nested
313
+ * under `transform`. This method marshals the caller-facing `rot`/`pos` (matching the
314
+ * panorama/node transform naming) onto that shape before POSTing.
315
+ *
316
+ * @param projectId The ID of the project the map belongs to.
317
+ * @param mapId The ID of the map to add the edge to.
318
+ * @param body The transform edge to add. `id` is optional; when omitted the server derives it.
319
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
320
+ */
321
+ addTransformEdge(projectId: string, mapId: string, body: AddTransformEdgeRequest): Promise<AddEdgeResponse>;
322
+ /**
323
+ * Delete a single edge by id from a map. Idempotent — a missing edge still returns
324
+ * success. Reserved/server-managed edge types and edges touching server-managed nodes are
325
+ * refused with 400.
326
+ *
327
+ * Access rules match {@link deleteNode} (deleting has a larger blast radius than adding):
328
+ * the environment map is always off-limits; the dronedeploy map is deletable only by admin
329
+ * users (server enforces via 401/403); normal maps are deletable by any caller with project
330
+ * access.
331
+ *
332
+ * @param projectId The ID of the project the map belongs to.
333
+ * @param mapId The ID of the map to delete the edge from.
334
+ * @param edgeId The ID of the edge to delete.
335
+ */
336
+ deleteEdge(projectId: string, mapId: string, edgeId: string): Promise<void>;
232
337
  }
@@ -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_PANORAMAS_URL, 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_EDGES_ADD_TRANSFORM_URL, API_GRAPHS_MAP_EDGES_ADD_URL, API_GRAPHS_MAP_EDGE_URL, API_GRAPHS_MAP_ID_URL, API_GRAPHS_MAP_METADATA_URL, API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL, API_GRAPHS_MAP_NODES_ADD_URL, API_GRAPHS_MAP_NODE_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';
@@ -310,4 +310,145 @@ export class MapService extends BaseServiceAbstract {
310
310
  deletePanorama(projectId, panoramaId) {
311
311
  return this.callDelete(formatServiceUrl(API_GRAPHS_PANORAMA, { url: this.config.url, projectId, panoramaId }, this.config.insecure), 'Failed to delete panorama.');
312
312
  }
313
+ /**
314
+ * Add a single node to an existing map. A low-impact, targeted alternative to replacing the
315
+ * whole map via {@link create} — same access surface (permitted on the reserved dronedeploy
316
+ * map and on normal maps; the environment map remains off-limits).
317
+ *
318
+ * Create-only: a duplicate id in the target map is rejected with 409 rather than being
319
+ * silently upserted, to keep the blast radius small on the shared dronedeploy map.
320
+ * Server-managed types (`SUMMARY`, `CALLSIGN`, `GeoScene`, `MAP_INFO`) are refused with
321
+ * 400. Adding to a map that doesn't exist returns 404.
322
+ *
323
+ * @param projectId The ID of the project the map belongs to.
324
+ * @param mapId The ID of the map to add the node to.
325
+ * @param body The node to add.
326
+ * @returns The id of the created node (echoes `body.id`).
327
+ */
328
+ addNode(projectId, mapId, body) {
329
+ return this.callPost(formatServiceUrl(API_GRAPHS_MAP_NODES_ADD_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), body, 'Failed to add node.');
330
+ }
331
+ /**
332
+ * Add a single node **and** a `TRANSFORM` edge that positions it under an existing frame
333
+ * node in the same map, by the supplied rotation + position. Same access rules and
334
+ * create-only semantics as {@link addNode}.
335
+ *
336
+ * The parent frame node (`body.transform.parent`) must already exist in the target map —
337
+ * a missing frame is rejected with 400, and a frame that vanishes between the pre-check
338
+ * and the write returns 409 (the transaction rolls back so no orphan node is created).
339
+ *
340
+ * Wire-shape note: the server currently receives `frame` as a top-level field alongside
341
+ * `transform`, and expects the position under the wire name `translation`. This method
342
+ * marshals the caller-facing {@link AddTransformableNodeRequest} (which carries `parent`
343
+ * inline in `transform` and uses `pos`/`rot` to match the panorama transform) onto that
344
+ * shape before POSTing.
345
+ *
346
+ * @param projectId The ID of the project the map belongs to.
347
+ * @param mapId The ID of the map to add the node to.
348
+ * @param body The node to add plus the transform that positions it under a parent frame.
349
+ * @returns The id of the created node (echoes `body.id`).
350
+ */
351
+ addTransformableNode(projectId, mapId, body) {
352
+ // Translate the caller-facing shape (parent inline in `transform`, `pos`/`rot`) onto the
353
+ // server's wire shape (`frame` at the top level, `translation`/`rotation` inside
354
+ // `transform`). Rationale for the divergence: the SDK type keeps `AffineTransform` well
355
+ // formed in isolation and mirrors the `Panorama.transform` naming (`pos`/`rot`); the
356
+ // server predates this convention and hasn't been migrated yet.
357
+ const wireBody = {
358
+ id: body.id,
359
+ type: body.type,
360
+ data: body.data,
361
+ frame: body.transform.parent,
362
+ transform: {
363
+ rotation: body.transform.rot,
364
+ translation: body.transform.pos,
365
+ },
366
+ };
367
+ return this.callPost(formatServiceUrl(API_GRAPHS_MAP_NODES_ADD_TRANSFORMABLE_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), wireBody, 'Failed to add transformable node.');
368
+ }
369
+ /**
370
+ * Delete a single node (and any edges attached to it) from a map. Idempotent — a missing
371
+ * node still returns success. Refuses server-managed types (`SUMMARY`, `CALLSIGN`,
372
+ * `GeoScene`, `MAP_INFO`) with 400.
373
+ *
374
+ * Access rules differ from the add endpoints because deleting has a larger blast radius:
375
+ * the environment map is always off-limits; the dronedeploy map is deletable only by
376
+ * admin users (server enforces via 401/403); normal maps are deletable by any caller with
377
+ * project access.
378
+ *
379
+ * @param projectId The ID of the project the map belongs to.
380
+ * @param mapId The ID of the map to delete the node from.
381
+ * @param nodeId The ID of the node to delete.
382
+ */
383
+ deleteNode(projectId, mapId, nodeId) {
384
+ return this.callDelete(formatServiceUrl(API_GRAPHS_MAP_NODE_URL, { url: this.config.url, projectId, mapId, nodeId }, this.config.insecure), 'Failed to delete node.');
385
+ }
386
+ /**
387
+ * Add a single edge between two existing nodes in a map. The edge-side counterpart of
388
+ * {@link addNode}: a low-impact, targeted alternative to replacing the whole map — same
389
+ * access surface (permitted on the reserved dronedeploy map and on normal maps; the
390
+ * environment map remains off-limits).
391
+ *
392
+ * Create-only: a colliding edge id is rejected with 409 rather than upserted. Reserved
393
+ * edge types (`ALIAS`, `DEPLOYED`) and edges touching server-managed nodes are refused
394
+ * with 400, both endpoint nodes must already exist (400 otherwise), and a `TRANSFORM`
395
+ * edge must carry a valid `data.TransformMatrix` (use {@link addTransformEdge} to build
396
+ * one from a rotation + position). Adding to a map that doesn't exist returns 404.
397
+ *
398
+ * @param projectId The ID of the project the map belongs to.
399
+ * @param mapId The ID of the map to add the edge to.
400
+ * @param body The edge to add. `id` is optional; when omitted the server derives it.
401
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
402
+ */
403
+ addEdge(projectId, mapId, body) {
404
+ return this.callPost(formatServiceUrl(API_GRAPHS_MAP_EDGES_ADD_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), body, 'Failed to add edge.');
405
+ }
406
+ /**
407
+ * Add a single `TRANSFORM` edge from one existing node to another, positioning the `to`
408
+ * node relative to the `from` node by the supplied rotation + position. A specialisation
409
+ * of {@link addEdge} with the type fixed to `TRANSFORM` and the matrix built server-side;
410
+ * same access rules and create-only semantics.
411
+ *
412
+ * Both endpoint nodes must already exist in the target map (400 otherwise).
413
+ *
414
+ * Wire-shape note: the server receives the transform as `{ rotation, translation }` nested
415
+ * under `transform`. This method marshals the caller-facing `rot`/`pos` (matching the
416
+ * panorama/node transform naming) onto that shape before POSTing.
417
+ *
418
+ * @param projectId The ID of the project the map belongs to.
419
+ * @param mapId The ID of the map to add the edge to.
420
+ * @param body The transform edge to add. `id` is optional; when omitted the server derives it.
421
+ * @returns The id of the created edge (echoes `body.id`, or the server-derived id).
422
+ */
423
+ addTransformEdge(projectId, mapId, body) {
424
+ // Translate the caller-facing `rot`/`pos` onto the server's wire shape
425
+ // (`transform.rotation`/`transform.translation`), mirroring addTransformableNode.
426
+ const wireBody = {
427
+ id: body.id,
428
+ from: body.from,
429
+ to: body.to,
430
+ transform: {
431
+ rotation: body.transform.rot,
432
+ translation: body.transform.pos,
433
+ },
434
+ };
435
+ return this.callPost(formatServiceUrl(API_GRAPHS_MAP_EDGES_ADD_TRANSFORM_URL, { url: this.config.url, projectId, mapId }, this.config.insecure), wireBody, 'Failed to add transform edge.');
436
+ }
437
+ /**
438
+ * Delete a single edge by id from a map. Idempotent — a missing edge still returns
439
+ * success. Reserved/server-managed edge types and edges touching server-managed nodes are
440
+ * refused with 400.
441
+ *
442
+ * Access rules match {@link deleteNode} (deleting has a larger blast radius than adding):
443
+ * the environment map is always off-limits; the dronedeploy map is deletable only by admin
444
+ * users (server enforces via 401/403); normal maps are deletable by any caller with project
445
+ * access.
446
+ *
447
+ * @param projectId The ID of the project the map belongs to.
448
+ * @param mapId The ID of the map to delete the edge from.
449
+ * @param edgeId The ID of the edge to delete.
450
+ */
451
+ deleteEdge(projectId, mapId, edgeId) {
452
+ return this.callDelete(formatServiceUrl(API_GRAPHS_MAP_EDGE_URL, { url: this.config.url, projectId, mapId, edgeId }, this.config.insecure), 'Failed to delete edge.');
453
+ }
313
454
  }
@@ -2,6 +2,7 @@ import { Observable } from 'rxjs';
2
2
  import { CallsignStatus, IRocosSDKConfig, IRocosTelemetryMessage, IStreamStatusMessage, ITelemetryStream, ITelemetryStreamConfig, ITelemetrySubscriptionParams, ITelemetrySubscriptions, TelemetryMonitorStatus } from '../models';
3
3
  import { BaseStreamService } from './BaseStreamService';
4
4
  export declare class TelemetryService extends BaseStreamService<ITelemetryStream, ITelemetryStreamConfig> {
5
+ private static grpcWebDeprecationWarned;
5
6
  private statusSubscription;
6
7
  private changeStream$;
7
8
  private streamStatusSubject$;
@@ -174,9 +174,15 @@ export class TelemetryService extends BaseStreamService {
174
174
  return newStream.stream;
175
175
  }
176
176
  getStream(config) {
177
- if (config.transport === 'connect') {
178
- return new TelemetryStreamConnect(config);
177
+ if (config.transport === 'grpc-web') {
178
+ if (!TelemetryService.grpcWebDeprecationWarned) {
179
+ TelemetryService.grpcWebDeprecationWarned = true;
180
+ this.logger.warn('The grpc-web telemetry transport is deprecated and will be removed in a future release. ' +
181
+ 'Switch to the Connect protocol by setting transport to "connect" (now the default).');
182
+ }
183
+ return new TelemetryStream(config);
179
184
  }
180
- return new TelemetryStream(config);
185
+ return new TelemetryStreamConnect(config);
181
186
  }
182
187
  }
188
+ TelemetryService.grpcWebDeprecationWarned = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dronedeploy/rocos-js-sdk",
3
- "version": "3.1.8",
3
+ "version": "4.1.0",
4
4
  "description": "Javascript SDK for rocos",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",