From 01e0331219a10519c8542603246bcf2478c10210 Mon Sep 17 00:00:00 2001 From: viambot <79611529+viambot@users.noreply.github.com> Date: Mon, 24 Nov 2025 15:44:12 +0000 Subject: [PATCH] [WORKFLOW] AI update based on proto changes from commit 4676591c06c0f1e841295415281ba6a43eaac69f --- src/app/data-client.spec.ts | 50 ++++++++++++++++++++++++++++++++- src/app/data-client.ts | 41 +++++++++++++++++++++++++++ src/components/gantry/client.ts | 30 ++++++++++++++++++-- src/components/gantry/gantry.ts | 32 ++++++++++++++++++++- 4 files changed, 149 insertions(+), 4 deletions(-) diff --git a/src/app/data-client.spec.ts b/src/app/data-client.spec.ts index f4c896fd6..63e415b81 100644 --- a/src/app/data-client.spec.ts +++ b/src/app/data-client.spec.ts @@ -25,6 +25,8 @@ import { ConfigureDatabaseUserResponse, CreateIndexRequest, CreateIndexResponse, + CreateBinaryDataSignedURLRequest, + CreateBinaryDataSignedURLResponse, DataRequest, DeleteBinaryDataByFilterRequest, DeleteBinaryDataByFilterResponse, @@ -1229,6 +1231,52 @@ describe('DataClient tests', () => { }); }); + describe('createBinaryDataSignedURL tests', () => { + const binaryDataId = 'testBinaryDataId'; + const signedUrl = 'https://example.com/signed-url'; + const expiresAt = new Date(2025, 0, 1, 12, 0, 0); // Jan 1, 2025 12:00:00 + const expirationMinutes = 60; + + let capReq: CreateBinaryDataSignedURLRequest; + beforeEach(() => { + mockTransport = createRouterTransport(({ service }) => { + service(DataService, { + createBinaryDataSignedURL: (req) => { + capReq = req; + return new CreateBinaryDataSignedURLResponse({ + signedUrl, + expiresAt: Timestamp.fromDate(expiresAt), + }); + }, + }); + }); + }); + + it('creates a binary data signed URL with default expiration', async () => { + const expectedRequest = new CreateBinaryDataSignedURLRequest({ + binaryDataId, + }); + + const result = await subject().createBinaryDataSignedURL(binaryDataId); + expect(capReq).toStrictEqual(expectedRequest); + expect(result).toEqual({ signedUrl, expiresAt }); + }); + + it('creates a binary data signed URL with specified expiration', async () => { + const expectedRequest = new CreateBinaryDataSignedURLRequest({ + binaryDataId, + expirationMinutes, + }); + + const result = await subject().createBinaryDataSignedURL( + binaryDataId, + expirationMinutes + ); + expect(capReq).toStrictEqual(expectedRequest); + expect(result).toEqual({ signedUrl, expiresAt }); + }); + }); + describe('createFilter tests', () => { it('create empty filter', () => { const testFilter = DataClient.createFilter({}); @@ -2037,4 +2085,4 @@ describe('fileUpload tests', () => { expect(receivedData).toStrictEqual(data); }); -}); +}); \ No newline at end of file diff --git a/src/app/data-client.ts b/src/app/data-client.ts index 62e205a28..6d5462ae8 100644 --- a/src/app/data-client.ts +++ b/src/app/data-client.ts @@ -18,6 +18,8 @@ import { TabularDataSource, TabularDataSourceType, TagsFilter, + CreateBinaryDataSignedURLRequest, + CreateBinaryDataSignedURLResponse, } from '../gen/app/data/v1/data_pb'; import { DataPipelinesService } from '../gen/app/datapipelines/v1/data_pipelines_connect'; import { @@ -1737,6 +1739,43 @@ export class DataClient { pipelineName, }); } + + /** + * CreateBinaryDataSignedURL creates a temporary public URL for a binary data file. + * + * @example + * + * ```ts + * const { signedUrl, expiresAt } = await dataClient.createBinaryDataSignedURL( + * 'ccb74b53-1235-4328-a4b9-91dff1915a50/x5vur1fmps/YAEzj5I1kTwtYsDdf4a7ctaJpGgKRHmnM9bJNVyblk52UpqmrnMVTITaBKZctKEh', + * 60 // Expiration in minutes + * ); + * console.log('Signed URL:', signedUrl); + * console.log('Expires At:', expiresAt); + * ``` + * + * For more information, see [Data + * API](https://docs.viam.com/dev/reference/apis/data-client/#createbinarydatasignedurl). + * + * @param binaryDataId The binary data ID of the file to create a signed URL for. + * @param expirationMinutes Optional expiration time in minutes. Defaults to 15 minutes if not specified. + * Maximum allowed is 10080 minutes (7 days). + * @returns An object containing the signed URL and its expiration time. + */ + async createBinaryDataSignedURL( + binaryDataId: string, + expirationMinutes?: number + ): Promise<{ signedUrl: string; expiresAt: Date }> { + const req = new CreateBinaryDataSignedURLRequest({ + binaryDataId, + expirationMinutes, + }); + const resp = await this.dataClient.createBinaryDataSignedURL(req); + return { + signedUrl: resp.signedUrl, + expiresAt: resp.expiresAt!.toDate(), // eslint-disable-line @typescript-eslint/no-non-null-assertion + }; + } } export class ListDataPipelineRunsPage { @@ -1793,5 +1832,7 @@ export { type BinaryID, type IndexableCollection, type Order, + CreateBinaryDataSignedURLRequest, + CreateBinaryDataSignedURLResponse, } from '../gen/app/data/v1/data_pb'; export { type UploadMetadata } from '../gen/app/datasync/v1/data_sync_pb'; diff --git a/src/components/gantry/client.ts b/src/components/gantry/client.ts index 084772311..ee1b8484f 100644 --- a/src/components/gantry/client.ts +++ b/src/components/gantry/client.ts @@ -13,7 +13,7 @@ import type { RobotClient } from '../../robot'; import type { Options } from '../../types'; import { doCommandFromClient } from '../../utils'; import type { Gantry } from './gantry'; -import { GetGeometriesRequest } from '../../gen/common/v1/common_pb'; +import { GetGeometriesRequest, GetKinematicsRequest, GetKinematicsResponse, KinematicParamType } from '../../gen/common/v1/common_pb'; /** * A gRPC-web client for the Gantry component. @@ -42,6 +42,32 @@ export class GantryClient implements Gantry { return response.geometries; } + async getKinematics(extra = {}, callOptions = this.callOptions) { + const request = new GetKinematicsRequest({ + name: this.name, + extra: Struct.fromJson(extra), + }); + + this.options.requestLogger?.(request); + + const resp = await this.client.getKinematics(request, callOptions); + const { kinematicsData } = resp; + if (!kinematicsData) { + throw new Error('No kinematics data'); + } + return { + name: this.name, + kinematic_param_type: KinematicParamType[ + kinematicsData.kinematicParamType + ].replace('KINEMATIC_PARAM_TYPE_', '') as + | 'SVA' + | 'URDF' + | 'UNSPECIFIED', + joints: kinematicsData.joints, + links: kinematicsData.links, + }; + } + async getPosition(extra = {}, callOptions = this.callOptions) { const request = new GetPositionRequest({ name: this.name, @@ -130,4 +156,4 @@ export class GantryClient implements Gantry { callOptions ); } -} +} \ No newline at end of file diff --git a/src/components/gantry/gantry.ts b/src/components/gantry/gantry.ts index e2eabf628..88e6ddb0e 100644 --- a/src/components/gantry/gantry.ts +++ b/src/components/gantry/gantry.ts @@ -1,6 +1,8 @@ import type { Struct } from '@bufbuild/protobuf'; import type { Resource } from '../../types'; import type { Geometry } from '../../gen/common/v1/common_pb'; +import type { Frame } from '../../gen/app/v1/robot_pb'; +import type { Vector3 } from '../../types'; /** Represents a physical gantry that exists in three-dimensional space. */ export interface Gantry extends Resource { @@ -21,6 +23,34 @@ export interface Gantry extends Resource { */ getGeometries: (extra?: Struct) => Promise; + /** + * Get the kinematics information associated with the gantry. + * + * @example + * + * ```ts + * const gantry = new VIAM.GantryClient(machine, 'my_gantry'); + * const kinematics = await gantry.getKinematics(); + * console.log(kinematics); + * ``` + * + * For more information, see [Gantry + * API](https://docs.viam.com/dev/reference/apis/components/gantry/#getkinematics). + */ + getKinematics: (extra?: Struct) => Promise<{ + name: string; + kinematic_param_type: 'SVA' | 'URDF' | 'UNSPECIFIED'; + joints: { + id: string; + type: string; + parent: string; + axis: Vector3; + max: number; + min: number; + }[]; + links: Frame[]; + }>; + /** * Move each axis of the gantry to the positionsMm at the speeds in * speedsMmPerSec. @@ -144,4 +174,4 @@ export interface Gantry extends Resource { * API](https://docs.viam.com/dev/reference/apis/components/gantry/#ismoving). */ isMoving: () => Promise; -} +} \ No newline at end of file