alwaysai
Version:
The alwaysAI command-line interface (CLI)
402 lines (345 loc) • 10.7 kB
text/typescript
import { CliTerseError } from '@alwaysai/alwayscli';
import { PLEASE_REPORT_THIS_ERROR_MESSAGE } from '../constants';
import { serviceEndpointBuilder } from '../infrastructure/urls';
import { logger, stringifyError } from '../util';
import { CliAuthenticationClient } from './authentication-client';
import { getRestURL } from './urls';
export type DeviceMode = 'development' | 'production';
export type Cert = {
iotKeys: {
certificateArn: string;
certificateId: string;
certificatePem: string;
keyPair: {
PublicKey: string;
PrivateKey: string;
};
rootCA: string;
};
};
export type AddedDevice = {
deviceId: number;
deviceUUID: string;
accessToken: string;
refreshToken: string;
idToken: string;
iotKeys: {
certificateArn: string;
certificateId: string;
certificatePem: string;
keyPair: {
PublicKey: string;
PrivateKey: string;
};
rootCA: string;
};
};
export type AaiDevice = {
id: number;
uuid: string;
owner: string;
friendly_name: string;
description?: string;
host_name: string;
device_user_name?: string;
hardware_ids?: string;
device_hash?: string;
deleted: boolean;
created_at: string;
updated_at: string;
cognito_device_key?: string;
mode?: string;
iot_keys?: any;
status?: string;
device_log?: any;
unit?: string;
ip?: string;
coordinates?: any;
};
export type RefreshedDevice = {
accessToken: string;
refreshToken: string;
idToken: string;
};
export type ReleaseURLandKey = {
key: string;
presignedAppUrl: string;
};
export type ReleaseHistoryArray = ReleaseHistoryDict[];
export type ReleaseHistoryDict = {
name: string;
hash: string;
version: string;
timestamp: string;
releaseHash: string; // this is the same as hash
created_at: string;
size: number;
};
export type ApplicationPackage = {
tarFileName: string;
tarFile: Buffer;
releaseManifestName: string;
releaseManifestFile: string;
};
export type ApplicationRecord = {
hash: string;
s3Path: string;
projectId: number;
name: string;
};
export type PipelineChannel = {
name: string;
uuid: string;
};
export async function addDevice(device, deviceMode: DeviceMode) {
const { getIdAuthorizationHeader } = CliAuthenticationClient();
const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
const requestURL = `${getRestURL()}/createDeviceIot`;
const response = await fetch(requestURL, {
method: 'post',
body: JSON.stringify({ ...device, deviceMode }),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
});
if (response.status !== 200) {
logger.error(`addDevice: ${response.statusText}`);
throw new CliTerseError(
`addDevice: ${response.statusText}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
const readerStream = Buffer.from(await response.arrayBuffer());
const parsedJSon = JSON.parse(readerStream.toString());
return parsedJSon as AddedDevice;
}
export async function refreshDevice(deviceId: string) {
const { getIdAuthorizationHeader } = CliAuthenticationClient();
const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
const requestURL = `${getRestURL()}/refreshDevice`;
const response = await fetch(requestURL, {
method: 'post',
body: JSON.stringify({ deviceId }),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
});
if (response.status !== 200) {
logger.error(`refreshDevice: ${response.statusText}`);
throw new CliTerseError(
`refreshDevice: ${response.statusText}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
const readerStream = Buffer.from(await response.arrayBuffer());
const parsedJSon = JSON.parse(readerStream.toString());
return parsedJSon as RefreshedDevice;
}
interface UploadResult {
uploadURL: string;
}
export async function getPresignedUrlAppUpload(
fileName: string,
fileType: string
): Promise<UploadResult> {
const { getIdAuthorizationHeader } = CliAuthenticationClient();
const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
const requestURL = serviceEndpointBuilder(
'remote-deployment',
'presigned-url-app-upload'
);
const response = await fetch(requestURL, {
method: 'post',
body: JSON.stringify({ fileName, fileType }),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
});
if (response.status !== 200) {
logger.error(`get-presigned-url-app-upload: ${response.statusText}`);
throw new CliTerseError(
`get-presigned-url-app-upload: ${response.statusText}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
const readerStream = Buffer.from(await response.arrayBuffer());
const parsedJSon = JSON.parse(readerStream.toString());
return parsedJSon;
}
export async function usePresignedUrlAppUpload(
presignedUrl: string,
fileStream: any
) {
try {
const response = await fetch(presignedUrl, {
method: 'PUT',
body: fileStream,
headers: {
'Content-Type': 'application/octet-stream'
}
});
if (response.status !== 200) {
logger.error(`use-presigned-url-app-upload: ${response.statusText}`);
throw new CliTerseError(
`use-presigned-url-app-upload: ${response.statusText}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
} catch (error) {
logger.error(stringifyError(error));
throw new CliTerseError(
`app-upload: ${stringifyError(
error
)} ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
}
export async function insertAppRecord(record: ApplicationRecord) {
const { getIdAuthorizationHeader } = CliAuthenticationClient();
const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
const response = await fetch(
serviceEndpointBuilder('remote-deployment', 'create-application-release'),
{
method: 'post',
body: JSON.stringify({ ...record }),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
}
);
const readerStream = Buffer.from(await response.arrayBuffer());
const jsonStr = readerStream.toString();
if (response.status !== 200) {
logger.error(`insertAppRecord: ${jsonStr}`);
throw new CliTerseError(
`insertAppRecord: ${jsonStr}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
}
export async function getReleaseURL(projectId: string, releaseHash?: string) {
const { getIdAuthorizationHeader } = CliAuthenticationClient();
const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
const requestURL = serviceEndpointBuilder(
'remote-deployment',
'get-presigned-app-url'
);
const response = await fetch(requestURL, {
method: 'post',
body: JSON.stringify({ projectId, releaseHash }),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
});
if (response.status !== 200) {
logger.error(`getReleaseUrl: ${response.statusText}`);
throw new CliTerseError(
`getReleaseUrl: ${response.statusText}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
const readerStream = Buffer.from(await response.arrayBuffer());
const parsedJSon = JSON.parse(readerStream.toString());
return parsedJSon as ReleaseURLandKey;
}
export async function fetchAppReleaseHistory(projectUuid: string) {
const { getIdAuthorizationHeader } = CliAuthenticationClient();
const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
const requestURL = serviceEndpointBuilder(
'remote-deployment',
'get-app-release-history'
);
const response = await fetch(requestURL, {
method: 'post',
body: JSON.stringify({ projectUuid }),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
});
if (response.status !== 200) {
logger.error(`fetchAppReleaseHistory: ${response.statusText}`);
throw new CliTerseError(
`fetchAppReleaseHistory: ${response.statusText}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
const readerStream = Buffer.from(await response.arrayBuffer());
const parsedJSon = JSON.parse(readerStream.toString());
return parsedJSon as ReleaseHistoryArray;
}
export async function getDeviceByUuid({
uuid
}: {
uuid: string;
}): Promise<AaiDevice> {
const { getIdAuthorizationHeader } = CliAuthenticationClient();
const idTokenAuthorizationHeader = await getIdAuthorizationHeader();
const requestURL = serviceEndpointBuilder('devices', 'get-device-by-uuid');
const response = await fetch(requestURL, {
method: 'post',
body: JSON.stringify({ uuid }),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
});
if (response.status !== 200) {
logger.error(`get-device-by-uuid: ${response.statusText}`);
throw new CliTerseError(
`get-device-by-uuid: ${response.statusText}. ${PLEASE_REPORT_THIS_ERROR_MESSAGE}`
);
}
const readerStream = Buffer.from(await response.arrayBuffer());
const parsedJson = JSON.parse(readerStream.toString());
return parsedJson as AaiDevice;
}
export async function createAnalyticsPipeline(
pipelineName: string,
idTokenAuthorizationHeader: Record<string, string>
): Promise<PipelineChannel> {
const response = await fetch(
serviceEndpointBuilder('aai-analytics', 'createAnalyticsPipeline'),
{
method: 'POST',
body: JSON.stringify({
name: pipelineName
}),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
}
);
if (response.status !== 200) {
logger.error(`createPipeline failed: ${response.statusText}`);
throw new CliTerseError(`createPipeline failed: ${response.statusText}`);
}
const pipeline: PipelineChannel = (await response.json()) as PipelineChannel;
return pipeline;
}
export async function fetchAnalyticsPipelinesForOrg(
idTokenAuthorizationHeader: Record<string, string>
): Promise<PipelineChannel[]> {
const response = await fetch(
serviceEndpointBuilder(
'aai-analytics',
'getAnalyticsChannelIdsForOrganization'
),
{
method: 'POST',
body: JSON.stringify({}),
headers: {
...idTokenAuthorizationHeader,
'Content-Type': 'application/json'
}
}
);
if (response.status !== 200) {
logger.error(`fetchPipelinesForOrg failed: ${response.statusText}`);
throw new CliTerseError(
`fetchPipelinesForOrg failed: ${response.statusText}`
);
}
const orgPipelines: PipelineChannel[] =
(await response.json()) as PipelineChannel[];
return orgPipelines;
}