@inweb/client
Version:
JavaScript REST API client for the Open Cloud Server
1,120 lines (1,051 loc) • 40.1 kB
text/typescript
///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
// This application incorporates Open Design Alliance software pursuant to a
// license agreement with Open Design Alliance.
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
// All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////
import { EventEmitter2 } from "@inweb/eventemitter2";
import { IHttpClient } from "./IHttpClient";
import { HttpClient } from "./HttpClient";
import { FetchError } from "./FetchError";
import { ClientEventMap } from "./ClientEvents";
import { Assembly } from "./Assembly";
import { File } from "./File";
import { Job } from "./Job";
import { Project } from "./Project";
import { User } from "./User";
import { OAuthClient } from "./OAuthClient";
import { ISharedLinkPermissions } from "./ISharedLink";
import { SharedLink } from "./SharedLink";
import { SharedFile } from "./SharedFile";
import { parseArgs } from "./Utils";
/**
* Provides methods for managing Open Cloud Server resources such as users, files, assemblies, jobs,
* projects, etc.
*/
export class Client extends EventEmitter2<ClientEventMap> {
private _serverUrl = "";
private _httpClient: IHttpClient = new HttpClient("");
private _user: User | null = null;
public eventEmitter: EventEmitter2 = this;
/**
* @param params - An object containing client configuration parameters.
* @param params.serverUrl - Open Cloud REST API server URL.
* @param params.url - Deprecated since `25.8`. Use `serverUrl` instead.
*/
constructor(params: { serverUrl?: string; url?: string } = {}) {
super();
this.configure(params);
}
/**
* Open Cloud REST API server URL. Use {@link configure | configure()} to change server URL.
*
* @readonly
*/
get serverUrl(): string {
return this._serverUrl;
}
/**
* HTTP client instance used to send requests to the REST API server.
*
* @readonly
*/
get httpClient(): IHttpClient {
return this._httpClient;
}
/**
* Deprecated since `25.3`. Use `Viewer.options()` instead to change `Viewer` parameters.
*
* @deprecated
*/
get options(): any {
console.warn(
"Client.options has been deprecated since 25.3 and will be removed in a future release, use Viewer.options instead."
);
const data = {
showWCS: true,
cameraAnimation: true,
antialiasing: true,
groundShadow: false,
shadows: false,
cameraAxisXSpeed: 4,
cameraAxisYSpeed: 1,
ambientOcclusion: false,
enableStreamingMode: true,
enablePartialMode: false,
memoryLimit: 3294967296,
cuttingPlaneFillColor: { red: 0xff, green: 0x98, blue: 0x00 },
edgesColor: { r: 0xff, g: 0x98, b: 0x00 },
facesColor: { r: 0xff, g: 0x98, b: 0x00 },
edgesVisibility: true,
edgesOverlap: true,
facesOverlap: false,
facesTransparancy: 200,
enableCustomHighlight: true,
sceneGraph: false,
edgeModel: true,
reverseZoomWheel: false,
enableZoomWheel: true,
enableGestures: true,
};
return {
...data,
data,
defaults: () => data,
resetToDefaults: () => {},
saveToStorage: () => {},
loadFromStorage: () => {},
};
}
/**
* Changes the client parameters.
*
* After changing the parameters, you must re-login.
*
* @param params - An object containing new parameters.
* @param params.serverUrl - Open Cloud REST API server URL.
*/
configure(params: { serverUrl?: string }): this {
this._serverUrl = (params.serverUrl || "").replace(/\/+$/, "");
this._httpClient = new HttpClient(this.serverUrl);
this._user = null;
return this;
}
/**
* Returns client and server versions.
*
* No login is required to obtain the version.
*/
version(): Promise<{ server: string; client: string; hash: string }> {
return this.httpClient
.get("/version")
.then((response) => response.json())
.then((data) => ({
...data,
server: data.version,
client: "CLIENT_JS_VERSION",
}));
}
/**
* Registers a new user on the server.
*
* No login is required to register a new user.
*
* @param email - User email. Cannot be empty. Must be unique within the server.
* @param password - User password. Cannot be empty. Password can only contain letters (a-z, A-Z),
* numbers (0-9), and special characters (~!@#$%^&*()_-+={}[]<>|/'":;.,?).
* @param userName - User name. Cannot be empty or blank if defined. this to `undefined` to use
* `username` from email.
*/
registerUser(email: string, password: string, userName?: string): Promise<any> {
return this.httpClient
.post("/register", {
email,
password,
userName: userName ?? (email + "").split("@").at(0),
})
.then((response) => response.json());
}
/**
* Resends a Confirmation Email to the new user. If the user's email is already confirmed, an exception
* will be thrown.
*
* @param email - User email.
* @param password - User password.
*/
resendConfirmationEmail(email: string, password: string): Promise<any> {
return this.httpClient
.post("/register/email-confirmation", { email, password })
.then((response) => response.json());
}
/**
* Marks the user's email address as confirmed. If the user's email is already confirmed, an exception
* will be thrown.
*
* @param emailConfirmationId - Confirmation code from the Confirmation Email.
*/
confirmUserEmail(emailConfirmationId: string): Promise<any> {
return this.httpClient
.get(`/register/email-confirmation/${emailConfirmationId}`)
.then((response) => response.json());
}
/**
* Log in an existing user using email or user name.
*
* @param email - An email or user name for authentication request.
* @param password - Password for authentication request.
*/
async signInWithEmail(email: string, password: string): Promise<User> {
const credentials = btoa(unescape(encodeURIComponent(email + ":" + password)));
this.httpClient.headers["Authorization"] = "Basic " + credentials;
const response = await this.httpClient.get("/token");
const data = await response.json();
return this.setCurrentUser(data);
}
/**
* Log in an existing user using access token (API Key).
*
* @param token - An access token for authentication request. See {@link User.token} for more details.
*/
async signInWithToken(token: string): Promise<User> {
this.httpClient.headers["Authorization"] = token;
const response = await this.httpClient.get("/user");
const data = await response.json();
return this.setCurrentUser(data);
}
/**
* Log out.
*
* You must log in again using {@link signInWithEmail} or {@link signInWithToken} to continue making
* requests to the server
*/
signOut(): void {
this.clearCurrentUser();
}
// Save the current logged in user information for internal use.
private setCurrentUser(data: any): User {
this._user = new User(data, this.httpClient);
this.httpClient.headers["Authorization"] = data.tokenInfo.token;
this.httpClient.signInUserId = this._user.id;
this.httpClient.signInUserIsAdmin = this._user.isAdmin;
return this._user;
}
private clearCurrentUser(): void {
this._user = null;
delete this.httpClient.headers["Authorization"];
this.httpClient.signInUserId = "";
this.httpClient.signInUserIsAdmin = false;
}
/**
* Returns the current logged in user. Returns `null` if the user is not logged in or the logged in
* user has deleted themself.
*/
getCurrentUser(): User | null {
if (this._user && !this.httpClient.signInUserId) this._user = null;
return this._user;
}
/**
* Returns the list of server enabled indentity providers.
*/
getIdentityProviders(): Promise<{ name: string; url: string }[]> {
return this.httpClient.get("/identity").then((response) => response.json());
}
/**
* Returns the current server settings.
*
* @returns Returns an object with server settings. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Settings | Open Cloud Settings API}.
*/
getServerSettings(): Promise<any> {
return this.httpClient.get("/settings").then((response) => response.json());
}
/**
* Changes the server settings.
*
* Only administrators can change server settings. If the current logged in user is not an
* administrator, an exception will be thrown.
*
* @param settings - An object with the new server settings or part of the settings. For more
* information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Settings | Open Cloud Settings API}.
* @returns Returns an object with updated server settings.
*/
updateServerSettings(settings: any): Promise<any> {
return this.httpClient.put("/settings", settings).then((response) => response.json());
}
/**
* Result for OAuth client list.
*
* @typedef {any} OAuthClientsResult
* @property {OAuthClient[]} result - Result client list.
* @property {number} start - The starting index in the client list in the request.
* @property {number} limit - The maximum number of requested clients.
* @property {number} allSize - Total number of OAuth clients on the server.
* @property {number} size - The number of clients in the result list.
*/
/**
* Returns a list of OAuth clients of the server.
*
* Only administrators can get a list of OAuth clients. If the current logged in user is not an
* administrator, an exception will be thrown.
*
* @param start - The starting index in the client list. Used for paging.
* @param limit - The maximum number of clients that should be returned per request. Used for paging.
*/
getOAuthClients(
start?: number,
limit?: number
): Promise<{
result: OAuthClient[];
start: number;
limit: number;
allSize: number;
size: number;
}> {
const searchParams = new URLSearchParams();
if (start > 0) searchParams.set("start", start.toString());
if (limit > 0) searchParams.set("limit", limit.toString());
let queryString = searchParams.toString();
if (queryString) queryString = "?" + queryString;
return this.httpClient
.get(`/oauth/clients${queryString}`)
.then((response) => response.json())
.then((clients) => {
return {
...clients,
result: clients.result.map((data) => new OAuthClient(data, this.httpClient)),
};
});
}
/**
* Returns information about the specified OAuth client.
*
* Only administrators can get OAuth clients. If the current logged in user is not an administrator, an
* exception will be thrown.
*
* @param clientId - Client ID.
*/
getOAuthClient(clientId: string): Promise<OAuthClient> {
return this.httpClient
.get(`/oauth/clients/${clientId}`)
.then((response) => response.json())
.then((data) => new OAuthClient(data, this.httpClient));
}
/**
* Creates a new OAuth client on the server.
*
* Only administrators can create OAuth clients. If the current logged in user is not an administrator,
* an exception will be thrown.
*
* @param name - Client name.
* @param redirectUrl - Endpoint to which the OAuth 2.0 server sends the response.
* @param description - Client description.
*/
createOAuthClient(name: string, redirectUrl: string, description?: string): Promise<OAuthClient> {
return this.httpClient
.post("/oauth/clients", {
name,
redirectUrl,
description,
})
.then((response) => response.json())
.then((data) => new OAuthClient(data, this.httpClient));
}
/**
* Deletes the specified OAuth client from the server.
*
* Only administrators can delete OAuth clients. If the current logged in user is not an administrator,
* an exception will be thrown.
*
* @param clientId - Client ID.
* @returns Returns the raw data of a deleted client. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#OAuthClient | Open Cloud OAuth Clients API}.
*/
deleteOAuthClient(clientId: string): Promise<any> {
return this.httpClient.delete(`/oauth/clients/${clientId}`).then((response) => response.json());
}
/**
* Returns the list of server users.
*
* Only administrators can get a list of users. If the current logged in user is not an administrator,
* an exception will be thrown.
*/
getUsers(): Promise<User[]> {
return this.httpClient
.get("/users")
.then((response) => response.json())
.then((array) => array.map((data) => ({ id: data.id, ...data.userBrief })))
.then((array) => array.map((data) => new User(data, this.httpClient)));
}
/**
* Returns information about the specified user.
*
* Only administrators can get other users. If the current logged in user is not an administrator, they
* can only get themselves, otherwise an exception will be thrown.
*
* @param userId - User ID.
*/
getUser(userId: string): Promise<User> {
if (this.httpClient.signInUserIsAdmin) {
return this.httpClient
.get(`/users/${userId}`)
.then((response) => response.json())
.then((data) => ({ id: data.id, ...data.userBrief }))
.then((data) => new User(data, this.httpClient));
} else if (userId === this.httpClient.signInUserId) {
return this.httpClient
.get("/user")
.then((response) => response.json())
.then((data) => ({ id: userId, ...data }))
.then((data) => new User(data, this.httpClient));
} else {
return Promise.reject(new FetchError(403));
}
}
/**
* Creates a new user on the server.
*
* Only administrators can create users. If the current logged in user is not an administrator, an
* exception will be thrown.
*
* @param email - User email. Cannot be empty. Must be unique within the server.
* @param password - User password. Cannot be empty. Password can only contain latin letters (a-z,
* A-Z), numbers (0-9), and special characters (~!@#$%^&*()_-+={}[]<>|/'":;.,?).
* @param params - Additional user data.
* @param params.isAdmin - `true` if user is an administrator.
* @param params.userName - User name. Cannot be empty or blank if defined. Specify `undefined` to use
* `username` from email.
* @param params.firstName - First name.
* @param params.lastName - Last name.
* @param params.canCreateProject - `true` if user is allowed to create a project.
* @param params.projectsLimit - The maximum number of projects that the user can create.
* @param params.storageLimit - The size of the file storage available to the user in bytes.
*/
createUser(
email: string,
password: string,
params: {
isAdmin?: boolean;
userName?: string;
firstName?: string;
lastName?: string;
canCreateProject?: boolean;
projectsLimit?: number;
storageLimit?: number;
} = {}
): Promise<User> {
const { isAdmin, userName, ...rest } = params;
return this.httpClient
.post("/users", {
isAdmin,
userBrief: {
...rest,
email,
userName: userName ?? (email + "").split("@").at(0),
},
password,
})
.then((response) => response.json())
.then((data) => ({ id: data.id, ...data.userBrief }))
.then((data) => new User(data, this.httpClient));
}
/**
* Deletes the specified user from the server.
*
* Only administrators can delete users. If the current logged in user is not an administrator, an
* exception will be thrown.
*
* Administrators can delete themselves or other administrators. An administrator can only delete
* themself if they is not the last administrator.
*
* You need to re-login after deleting the current logged in user.
*
* @param userId - User ID.
* @returns Returns the raw data of a deleted user. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Users | Open Cloud Users API}.
*/
deleteUser(userId: string): Promise<any> {
if (this.httpClient.signInUserIsAdmin) {
return this.httpClient
.delete(`/users/${userId}`)
.then((response) => response.json())
.then((data) => {
if (userId === this.httpClient.signInUserId) {
this.clearCurrentUser();
}
return data;
});
} else {
return Promise.reject(new FetchError(403));
}
}
/**
* Result for file list.
*
* @typedef {any} FilesResult
* @property {File[]} result - Result file list.
* @property {number} start - The starting index in the file list in the request.
* @property {number} limit - The maximum number of requested files.
* @property {number} allSize - Total number of files the user has access to.
* @property {number} size - The number of files in the result list.
*/
/**
* Returns a list of files that the current logged in user has uploaded to the server or has access to.
*
* @param start - The starting index in the file list. Used for paging.
* @param limit - The maximum number of files that should be returned per request. Used for paging.
* @param name - Filter the files by part of the name. Case sensitive.
* @param ext - Filter the files by extension. Extension can be `dgn`, `dwf`, `dwg`, `dxf`, `ifc`,
* `ifczip`, `nwc`, `nwd`, `obj`, `rcs`, `rfa`, `rvt`, `step`, `stl`, `stp`, `vsf`, or any other file
* type extension.
* @param ids - List of file IDs to return.
* @param sortByDesc - Allows to specify the descending order of the result. By default, files are
* sorted by name in ascending order.
* @param sortField - Allows to specify sort field.
* @param shared - Returns shared files only.
*/
getFiles(
start?: number,
limit?: number,
name?: string,
ext?: string | string[],
ids?: string | string[],
sortByDesc?: boolean,
sortField?: string,
shared?: boolean
): Promise<{
result: File[];
start: number;
limit: number;
allSize: number;
size: number;
}> {
const searchParams = new URLSearchParams();
if (start > 0) searchParams.set("start", start.toString());
if (limit > 0) searchParams.set("limit", limit.toString());
if (name) searchParams.set("name", name);
if (ext) {
if (Array.isArray(ext)) ext = ext.join("|");
if (typeof ext === "string") ext = ext.toLowerCase();
if (ext) searchParams.set("ext", ext);
}
if (ids) {
if (Array.isArray(ids)) ids = ids.join("|");
searchParams.set("id", ids);
}
if (sortByDesc !== undefined) searchParams.set("sortBy", sortByDesc ? "desc" : "asc");
if (sortField) searchParams.set("sortField", sortField);
if (shared) searchParams.set("shared", "true");
let queryString = searchParams.toString();
if (queryString) queryString = "?" + queryString;
return this.httpClient
.get(`/files${queryString}`)
.then((response) => response.json())
.then((files) => {
return {
...files,
result: files.result.map((data) => new File(data, this.httpClient)),
};
});
}
/**
* Returns information about the specified file.
*
* @param fileId - File ID.
*/
getFile(fileId: string): Promise<File> {
return this.httpClient
.get(`/files/${fileId}`)
.then((response) => response.json())
.then((data) => new File(data, this.httpClient));
}
/**
* Upload a drawing or reference file to the server.
*
* Fires:
*
* - {@link UploadProgressEvent | uploadprogress}
*
* @param file - {@link https://developer.mozilla.org/docs/Web/API/File | Web API File} object are
* generally retrieved from a {@link https://developer.mozilla.org/docs/Web/API/FileList | FileList}
* object returned as a result of a user selecting files using the HTML `<input>` element.
* @param params - An object containing upload parameters.
* @param params.geometry - Create job to convert file geometry data. Can be:
*
* - `true` - Convert file geometry data to `VSFX` format to open the file in `VisualizeJS` viewer.
* - `vsfx` - Convert file geometry data to `VSFX` format to open the file in `VisualizeJS` viewer.
* - `gltf` - Convert file geometry data to `glTF` format to open the file in `Three.js` viewer.
*
* @param params.properties - Create job to extract file properties.
* @param params.waitForDone - Wait for geometry and properties jobs to complete.
* @param params.timeout - The time, in milliseconds that the function should wait jobs. If no one jobs
* are done during this time, the `TimeoutError` exception will be thrown.
* @param params.interval - The time, in milliseconds, the function should delay in between checking
* jobs status.
* @param params.signal - An
* {@link https://developer.mozilla.org/docs/Web/API/AbortController | AbortController} signal, which
* can be used to abort waiting as desired.
* @param params.onProgress - Upload progress callback.
*/
async uploadFile(
file: globalThis.File,
params: {
geometry?: boolean | string;
properties?: boolean;
waitForDone?: boolean;
timeout?: number;
interval?: number;
signal?: AbortSignal;
onProgress?: (progress: number, file: globalThis.File) => void;
} = {
geometry: true,
properties: false,
waitForDone: false,
}
): Promise<File> {
const result = await this.httpClient
.uploadFile("/files", file, (progress) => {
this.emitEvent({ type: "uploadprogress", data: progress, file });
params.onProgress?.(progress, file);
})
.then((xhr: XMLHttpRequest) => JSON.parse(xhr.responseText))
.then((data) => new File(data, this.httpClient));
const geometryType = typeof params.geometry === "string" ? params.geometry : "vsfx";
const jobs: string[] = [];
if (params.geometry) jobs.push((await result.extractGeometry(geometryType)).outputFormat);
if (params.properties) jobs.push((await result.extractProperties()).outputFormat);
if (jobs.length > 0)
if (params.waitForDone) await result.waitForDone(jobs, true, params);
else await result.checkout();
return result;
}
/**
* Deletes the specified file and all its versions from the server.
*
* You cannot delete a version file using `deleteFile()`, only the original file. To delete a version
* file use {@link File.deleteVersion | File.deleteVersion()}.
*
* @param fileId - File ID.
* @returns Returns the raw data of a deleted file. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Files | Open Cloud Files API}.
*/
deleteFile(fileId: string): Promise<any> {
return this.httpClient.delete(`/files/${fileId}`).then((response) => response.json());
}
/**
* Downloads the specified file from the server.
*
* @param fileId - File ID.
* @param onProgress - Download progress callback.
* @param signal - An
* {@link https://developer.mozilla.org/docs/Web/API/AbortController | AbortController} signal. Allows
* to communicate with a fetch request and abort it if desired.
*/
downloadFile(fileId: string, onProgress?: (progress: number) => void, signal?: AbortSignal): Promise<ArrayBuffer> {
return this.httpClient
.downloadFile(`/files/${fileId}/downloads`, onProgress, { signal })
.then((response) => response.arrayBuffer());
}
/**
* Result for job list.
*
* @typedef {any} JobsResult
* @property {Job[]} result - Result job list.
* @property {number} start - The starting index in the job list in the request.
* @property {number} limit - The maximum number of requested jobs.
* @property {number} allSize - Total number of jobs created by the user.
* @property {number} size - The number of jobs in the result list.
*/
/**
* Returns a list of jobs started by the current logged in user.
*
* @param status - Filter the jobs by status. Status can be `waiting`, `inpogress`, `done` or `failed`.
* @param limit - The maximum number of jobs that should be returned per request. Used for paging.
* @param start - The starting index in the job list. Used for paging.
* @param sortByDesc - Allows to specify the descending order of the result. By default, jobs are
* sorted by creation time in ascending order.
* @param {boolean} sortField - Allows to specify sort field.
*/
getJobs(
status?: string | string[],
limit?: number,
start?: number,
sortByDesc?: boolean,
sortField?: string
): Promise<{
result: Job[];
start: number;
limit: number;
allSize: number;
size: number;
}> {
const searchParams = new URLSearchParams();
if (start > 0) searchParams.set("start", start.toString());
if (limit > 0) searchParams.set("limit", limit.toString());
if (status) {
if (Array.isArray(status)) status = status.join("|");
if (typeof status === "string") status = status.trim().toLowerCase();
if (status) searchParams.set("status", status);
}
if (sortByDesc !== undefined) searchParams.set("sortBy", sortByDesc ? "desc" : "asc");
if (sortField) searchParams.set("sortField", sortField);
let queryString = searchParams.toString();
if (queryString) queryString = "?" + queryString;
return this.httpClient
.get(`/jobs${queryString}`)
.then((response) => response.json())
.then((jobs) => ({
...jobs,
result: jobs.result.map((data) => new Job(data, this.httpClient)),
}));
}
/**
* Returns information about the specified job.
*
* @param jobId - Job ID.
*/
getJob(jobId: string): Promise<Job> {
return this.httpClient
.get(`/jobs/${jobId}`)
.then((response) => response.json())
.then((data) => new Job(data, this.httpClient));
}
/**
* Runs a new job on the server for the sepecified file.
*
* @param fileId - File ID.
* @param outputFormat - The job type. Can be one of:
*
* - `geometry` - Convert file geometry data to `VSFX` format suitable for `VisualizeJS` viewer.
* - `geometryGltf` - Convert file geometry data to `glTF` format suitable for `Three.js` viewer.
* - `properties` - Extract file properties.
* - `validation` - Validate the file. Only for `IFC` files.
* - `dwg`, `obj`, `gltf`, `glb`, `vsf`, `pdf`, `3dpdf` - Export file to the one of the supported format.
* - Other custom job name. Custom job runner must be registered in the job templates table before
* creating a job.
*
* @param parameters - Parameters for the job runner. Can be given as command line arguments for the
* File Converter tool in form `--arg=value`.
*/
createJob(fileId: string, outputFormat: string, parameters?: string | object): Promise<Job> {
return this.httpClient
.post("/jobs", {
fileId,
outputFormat,
parameters: parseArgs(parameters),
})
.then((response) => response.json())
.then((data) => new Job(data, this.httpClient));
}
/**
* Deletes the specified job from the server job list. Jobs that are in progress or have already been
* completed cannot be deleted.
*
* @param jobId - Job ID.
* @returns Returns the raw data of a deleted job. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Jobs | Open Cloud Jobs API}.
*/
deleteJob(jobId: string): Promise<any> {
return this.httpClient.delete(`/jobs/${jobId}`).then((response) => response.json());
}
/**
* Result for assembly list.
*
* @typedef {any} AssembliesResult
* @property {Assembly[]} result - Result assembly list.
* @property {number} start - The starting index in the assembly list in the request.
* @property {number} limit - The maximum number of requested assemblies.
* @property {number} allSize - Total number of assemblies the user has access to.
* @property {number} size - The number of assemblies in the result list.
*/
/**
* Returns a list of assemblies created by the current logged in user.
*
* @param start - The starting index in the assembly list. Used for paging.
* @param limit - The maximum number of assemblies that should be returned per request. Used for
* paging.
* @param name - Filter the assemblies by part of the name. Case sensitive.
* @param ids - List of assembly IDs to return.
* @param sortByDesc - Allows to specify the descending order of the result. By default assemblies are
* sorted by name in ascending order.
* @param sortField - Allows to specify sort field.
*/
getAssemblies(
start?: number,
limit?: number,
name?: string,
ids?: string | string[],
sortByDesc?: boolean,
sortField?: string
): Promise<{
result: Assembly[];
start: number;
limit: number;
allSize: number;
size: number;
}> {
const searchParams = new URLSearchParams();
if (start > 0) searchParams.set("start", start.toString());
if (limit > 0) searchParams.set("limit", limit.toString());
if (name) searchParams.set("name", name);
if (ids) {
if (Array.isArray(ids)) ids = ids.join("|");
if (typeof ids === "string") ids = ids.trim();
if (ids) searchParams.set("id", ids);
}
if (sortByDesc !== undefined) searchParams.set("sortBy", sortByDesc ? "desc" : "asc");
if (sortField) searchParams.set("sortField", sortField);
let queryString = searchParams.toString();
if (queryString) queryString = "?" + queryString;
return this.httpClient
.get(`/assemblies${queryString}`)
.then((response) => response.json())
.then((assemblies) => {
return {
...assemblies,
result: assemblies.result.map((data) => new Assembly(data, this.httpClient)),
};
});
}
/**
* Returns information about the specified assembly.
*
* @param assemblyId - Assembly ID.
*/
getAssembly(assemblyId: string): Promise<Assembly> {
return this.httpClient
.get(`/assemblies/${assemblyId}`)
.then((response) => response.json())
.then((data) => new Assembly(data, this.httpClient));
}
/**
* Creates a new assembly on the server.
*
* @param files - List of file IDs.
* @param name - Assembly name.
* @param params - Additional assembly creating parameters.
* @param params.waitForDone - Wait for assembly to be created.
* @param params.timeout - The time, in milliseconds, that the function should wait for the assembly to
* be created. If the assembly is not created within this time, a TimeoutError exception will be
* thrown.
* @param params.interval - The time, in milliseconds, the function should delay in between checking
* assembly status.
* @param params.signal - An
* {@link https://developer.mozilla.org/docs/Web/API/AbortController | AbortController} signal, which
* can be used to abort waiting as desired.
* @param params.onCheckout - Waiting progress callback. Return `true` to cancel waiting.
*/
createAssembly(
files: string[],
name: string,
params?: {
waitForDone?: boolean;
timeout?: number;
interval?: number;
signal?: AbortSignal;
onCheckout?: (assembly: Assembly, ready: boolean) => boolean;
}
): Promise<Assembly> {
const { waitForDone } = params ?? {};
return this.httpClient
.post("/assemblies", { name, files })
.then((response) => response.json())
.then((data) => new Assembly(data, this.httpClient))
.then((result) => (waitForDone ? result.waitForDone(params) : result));
}
/**
* Deletes the specified assembly from the server.
*
* @param assemblyId - Assembly ID.
* @returns Returns the raw data of a deleted assembly. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud API}.
*/
deleteAssembly(assemblyId: string): Promise<any> {
return this.httpClient.delete(`/assemblies/${assemblyId}`).then((response) => response.json());
}
/**
* Result for project list.
*
* @typedef {any} ProjectsResult
* @property {Project[]} result - Result project list.
* @property {number} start - The starting index in the project list in the request.
* @property {number} limit - The maximum number of requested projects.
* @property {number} allSize - Total number of projects the user has access to.
* @property {number} size - The number of projects in the result list.
*/
/**
* Returns a list of projects that the currently logged in user has created or has access to.
*
* @param start - The starting index in the project list. Used for paging.
* @param limit - The maximum number of projects that should be returned per request. Used for paging.
* @param name - Filter the projects by part of the name. Case sensitive.
* @param ids - List of project IDs to return.
* @param sortByDesc - Allows to specify the descending order of the result. By default projects are
* sorted by name in ascending order.
*/
getProjects(
start?: number,
limit?: number,
name?: string,
ids?: string | string[],
sortByDesc?: boolean
): Promise<{
result: Project[];
start: number;
limit: number;
allSize: number;
size: number;
}> {
const searchParams = new URLSearchParams();
if (start > 0) searchParams.set("start", start.toString());
if (limit > 0) searchParams.set("limit", limit.toString());
if (name) searchParams.set("name", name);
if (ids) {
if (Array.isArray(ids)) ids = ids.join("|");
if (typeof ids === "string") ids = ids.trim();
if (ids) searchParams.set("id", ids);
}
if (sortByDesc !== undefined) searchParams.set("sortBy", sortByDesc ? "desc" : "asc");
let queryString = searchParams.toString();
if (queryString) queryString = "?" + queryString;
return this.httpClient
.get(`/projects${queryString}`)
.then((response) => response.json())
.then((projects) => {
// fix for server 23.5 and below
if (Array.isArray(projects)) {
let result = projects;
if (ids) result = result.filter((x) => ids.includes(x.id));
if (name) result = result.filter((x) => x.name.includes(name));
if (limit > 0) {
const begin = start > 0 ? start : 0;
result = result.slice(begin, begin + limit);
}
return {
allSize: projects.length,
start,
limit,
result,
size: result.length,
};
}
return projects;
})
.then((projects) => {
return {
...projects,
result: projects.result.map((data) => new Project(data, this.httpClient)),
};
});
}
/**
* Returns information about the specified project.
*
* @param projectId - Project ID.
*/
getProject(projectId: string): Promise<Project> {
return this.httpClient
.get(`/projects/${projectId}`)
.then((response) => response.json())
.then((data) => new Project(data, this.httpClient));
}
/**
* Creates a new project on the server.
*
* @param name - Project name.
* @param description - Project description.
* @param startDate - Project start date.
* @param endDate - Project end date.
*/
createProject(
name: string,
description?: string,
startDate?: Date | string,
endDate?: Date | string
): Promise<Project> {
return this.httpClient
.post("/projects", {
name,
description,
startDate: startDate instanceof Date ? startDate.toISOString() : startDate,
endDate: endDate instanceof Date ? endDate.toISOString() : endDate,
})
.then((response) => response.json())
.then((data) => new Project(data, this.httpClient));
}
/**
* Deletes the specified project from the server.
*
* @param projectId - Project ID.
* @returns Returns the raw data of a deleted project. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
deleteProject(projectId: string): Promise<any> {
return this.httpClient
.delete(`/projects/${projectId}`)
.then((response) => response.text())
.then((text) => {
// fix for server 23.5 and below
try {
return JSON.parse(text);
} catch {
return { id: projectId };
}
});
}
/**
* Returns information about the specified file shared link.
*
* @param token - Shared link token.
*/
getSharedLink(token: string): Promise<SharedLink> {
return this.httpClient
.get(`/shares/${token}`)
.then((response) => response.json())
.then((data) => new SharedLink(data, this.httpClient));
}
/**
* Creates a shared link for the specified file.
*
* @param fileId - File ID.
* @param permissions - Share permissions.
*/
createSharedLink(fileId: string, permissions?: ISharedLinkPermissions): Promise<SharedLink> {
return this.httpClient
.post("/shares", {
fileId,
permissions,
})
.then((response) => response.json())
.then((data) => new SharedLink(data, this.httpClient));
}
/**
* Deletes the specified shared link.
*
* Only file owner can delete shared link. If the current logged in user is not a file owner, an
* exception will be thrown.
*
* @param token - Shared link token.
* @returns Returns the raw data of a deleted shared link. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#ShareLinks | Open Cloud SharedLinks API}.
*/
deleteSharedLink(token: string): Promise<any> {
return this.httpClient.delete(`/shares/${token}`).then((response) => response.json());
}
/**
* Returns information about a file from a shared link.
*
* Some file features are not available via shared link:
*
* - Updating file properties, preview, and viewpoints
* - Running file jobs
* - Managing file permissions
* - Managing file versions
* - Deleting file
*
* @param token - Shared link token.
* @param password - Password to get access to the file.
*/
getSharedFile(token: string, password?: string): Promise<File> {
return this.httpClient
.get(`/shares/${token}/info`, { headers: { "InWeb-Password": password } })
.then((response) => response.json())
.then((data) => new SharedFile(data, password, this.httpClient));
}
}