@inweb/client
Version:
JavaScript REST API client for the Open Cloud Server
5,554 lines • 235 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.ODA = global.ODA || {}, global.ODA.Api = global.ODA.Api || {})));
})(this, (function (exports) { 'use strict';
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Base class for the REST API endpoints.
*/
class Endpoint {
/**
* @ignore
* @param path - The API path of the endpoint relative to the REST API server URL of the specified HTTP
* client.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
* @param headers - Endpoint-specific HTTP headers.
*/
constructor(path, httpClient, headers = {}) {
this.path = path;
this.httpClient = httpClient;
this.headers = headers;
}
// Internal: append the `?version=` search param to the specified relative path.
appendVersionParam(relativePath) {
if (this._useVersion === undefined)
return relativePath;
const delimiter = relativePath.includes("?") ? "&" : "?";
return `${relativePath}${delimiter}version=${this._useVersion}`;
}
/**
* Returns the endpoint API path.
*
* @ignore
* @param relativePath - Nested endpoint relative path.
*/
getEndpointPath(relativePath) {
return this.appendVersionParam(`${this.path}${relativePath}`);
}
/**
* Sends the `GET` request to the endpoint.
*
* @ignore
* @param relativePath - Nested endpoint relative path.
* @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.
*/
get(relativePath, signal) {
return this.httpClient.get(this.getEndpointPath(relativePath), { signal, headers: this.headers });
}
/**
* Sends the `POST` request to the endpoint.
*
* @ignore
* @param relativePath - Nested endpoint relative path.
* @param body - Request body. Can be
* {@link https://developer.mozilla.org/docs/Web/API/FormData | FormData},
* {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer},
* {@link https://developer.mozilla.org/docs/Web/API/Blob/Blob | Blob}, JSON object or plain text.
*/
post(relativePath, body) {
return this.httpClient.post(this.getEndpointPath(relativePath), body, { headers: this.headers });
}
/**
* Sends the `PUT` request to the endpoint.
*
* @ignore
* @param relativePath - Nested endpoint relative path.
* @param body - Request body. Can be
* {@link https://developer.mozilla.org/docs/Web/API/FormData | FormData},
* {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer},
* {@link https://developer.mozilla.org/docs/Web/API/Blob/Blob | Blob}, JSON object or plain text.
*/
put(relativePath, body) {
return this.httpClient.put(this.getEndpointPath(relativePath), body, { headers: this.headers });
}
/**
* Sends the `DELETE` request to the endpoint.
*
* @ignore
* @param relativePath - Nested endpoint relative path.
*/
delete(relativePath) {
return this.httpClient.delete(this.getEndpointPath(relativePath), { headers: this.headers });
}
// Internal: append the `version` param to the endpoint requests.
useVersion(version) {
this._useVersion = version;
return this;
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
const STATUS_CODES = {
100: "Continue",
101: "Switching Protocols",
102: "Processing",
103: "Early Hints",
200: "OK",
201: "Created",
202: "Accepted",
203: "Non-Authoritative Information",
204: "No Content",
205: "Reset Content",
206: "Partial Content",
207: "Multi-Status",
208: "Already Reported",
226: "IM Used",
300: "Multiple Choices",
301: "Moved Permanently",
302: "Found",
303: "See Other",
304: "Not Modified",
305: "Use Proxy",
307: "Temporary Redirect",
308: "Permanent Redirect",
400: "Bad Request",
401: "Unauthorized",
402: "Payment Required",
403: "Forbidden",
404: "Not Found",
405: "Method Not Allowed",
406: "Not Acceptable",
407: "Proxy Authentication Required",
408: "Request Time-out",
409: "Conflict",
410: "Gone",
411: "Length Required",
412: "Precondition Failed",
413: "Payload Too Large",
414: "URI Too Long",
415: "Unsupported Media Type",
416: "Range Not Satisfiable",
417: "Expectation Failed",
418: "I'm a teapot",
421: "Misdirected Request",
422: "Unprocessable Entity",
423: "Locked",
424: "Failed Dependency",
425: "Too Early",
426: "Upgrade Required",
428: "Precondition Required",
429: "Too Many Requests",
431: "Header Fields Too Large",
451: "Unavailable For Legal Reasons",
500: "Internal Server Error",
501: "Not Implemented",
502: "Bad Gateway",
503: "Service Unavailable",
504: "Gateway Timeout",
505: "HTTP Version Not Supported",
506: "Variant Also Negotiates",
507: "Insufficient Storage",
508: "Loop Detected",
509: "Bandwidth Limit Exceeded",
510: "Not Extended",
511: "Network Authentication Required",
};
function statusText(status) {
return STATUS_CODES[status] || `Error ${status}`;
}
function error400(text, _default = "400") {
try {
return JSON.parse(text).description;
}
catch {
return _default;
}
}
/**
* The `FetchError` object indicates an error when request to Open Cloud Server could not be performed. A
* `FetchError` is typically (but not exclusively) thrown when a network error occurs, access denied, or
* object not found.
*/
class FetchError extends Error {
/**
* @property status - The {@link https://developer.mozilla.org/docs/Web/HTTP/Status | HTTP status code}
* of the response.
* @property message - Error message.
*/
constructor(status, message) {
super(message || statusText(status));
this.name = "FetchError";
this.status = status;
this.statusText = statusText(status);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for working with view of the {@link File | file} or
* {@link Assembly| assembly}. For example, for `dwg` it is a `Model` space or layout, and for `rvt` files
* it is a `3D` view.
*/
class Model extends Endpoint {
/**
* @param data - Raw model data received from the server.
* @param file - The file/assembly instance that owns the model.
*/
constructor(data, file) {
super(`${file.path}/downloads`, file.httpClient);
this._data = data;
this._file = file;
}
/**
* The `Assembly` instance that owns the model.
*
* @readonly
*/
get assembly() {
return this._file;
}
/**
* Raw model data received from the server.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
}
/**
* Scene description resource file name. Use {@link downloadResource | downloadResource()} to download
* scene description file.
*
* @readonly
*/
get database() {
return this.data.database;
}
/**
* `true` if this is default model.
*
* @readonly
*/
get default() {
return this.data.default;
}
/**
* The `File` instance that owns the model.
*
* @readonly
*/
get file() {
return this._file;
}
/**
* The ID of the file that owns the model.
*
* @readonly
*/
get fileId() {
return this.data.fileId;
}
/**
* The list of geometry data resource files. Use {@link downloadResource | downloadResource()} to
* download geometry data files.
*
* @readonly
*/
get geometry() {
return this.data.geometry;
}
/**
* Unique model ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* Model name.
*
* @readonly
*/
get name() {
return this.data.name;
}
/**
* Model owner type, matches the file extension this is model of the file, or `assembly` for
* assemblies.
*
* @readonly
*/
get type() {
return this.file.type;
}
// Reserved for future use.
get version() {
return this.data.version;
}
/**
* Returns model list with one item `self`.
*/
getModels() {
return Promise.resolve([this]);
}
/**
* Returns a model transformation.
*
* @param handle - Model handle.
*/
getModelTransformMatrix(handle) {
return this.file.getModelTransformMatrix(handle);
}
/**
* Sets or removes a model transformation.
*
* @param handle - Model handle.
* @param transform - Transformation matrix. Specify `undefined` to remove transformation.
*/
setModelTransformMatrix(handle, transform) {
return this.file.setModelTransformMatrix(handle, transform).then(() => this);
}
/**
* Returns a list of viewpoints of the owner file/assembly.
*/
getViewpoints() {
return this._file
.getViewpoints()
.then((array) => array.filter(({ custom_fields = {} }) => custom_fields.modelId === this.id || custom_fields.modelName === this.name));
}
/**
* Saves a new model owner file/assembly viewpoint to the server. To create a new viewpoint use
* `Viewer.createViewpoint()`.
*
* @param viewpoint - Viewpoint object.
*/
saveViewpoint(viewpoint) {
return this._file.saveViewpoint({
...viewpoint,
custom_fields: { ...viewpoint.custom_fields, modelId: this.id, modelName: this.name },
});
}
/**
* Deletes the specified viewpoint from the owner file/assembly.
*
* @param guid - Viewpoint GUID.
* @returns Returns the raw data of a deleted viewpoint.
*/
deleteViewpoint(guid) {
return this._file.deleteViewpoint(guid);
}
/**
* Returns viewpoint snapshot as base64-encoded
* {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL}.
*
* @param guid - Viewpoint GUID.
*/
getSnapshot(guid) {
return this._file.getSnapshot(guid);
}
/**
* Returns viewpoint snapshot data.
*
* @param guid - Viewpoint GUID.
* @param bitmapGuid - Bitmap GUID.
*/
getSnapshotData(guid, bitmapGuid) {
return this._file.getSnapshotData(guid, bitmapGuid);
}
/**
* Downloads a resource file. Resource files are files that contain model scene descriptions, or
* geometry data.
*
* @param dataId - Resource file name.
* @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.
*/
downloadResource(dataId, onProgress, signal) {
return this._file.downloadResource(dataId, onProgress, signal);
}
/**
* Downloads a part of resource file. Resource files are files that contain model scene descriptions,
* or geometry data.
*
* @param dataId - Resource file name.
* @param ranges - A ranges of resource file contents to download. See
* {@link https://developer.mozilla.org/docs/Web/HTTP/Guides/Range_requests | HTTP range requests} for
* more details.
* @param requestId - Specify a non-empty `requestId` to append the `?requestId=` search parameter to
* the server request. If specified, server-side caching may not work.
* @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.
*/
downloadResourceRange(dataId, requestId, ranges, onProgress, signal) {
return this._file.downloadResourceRange(dataId, requestId, ranges, onProgress, signal);
}
/**
* Deprecated since `25.3`. Use {@link downloadResource | downloadResource()} instead.
*
* @deprecated
*/
partialDownloadResource(dataId, onProgress, signal) {
console.warn("Model.partialDownloadResource() has been deprecated since 25.3 and will be removed in a future release, use Model.downloadResource() instead.");
return this.downloadResource(dataId, onProgress, signal);
}
/**
* Deprecated since `25.3`. Use {@link downloadResourceRange | downloadResourceRange()} instead.
*
* @deprecated
*/
async downloadFileRange(requestId, records, dataId, onProgress, signal) {
if (!records)
return;
let ranges = [];
if (records.length) {
ranges = records.map((record) => ({
begin: Number(record.begin),
end: Number(record.end),
requestId: record.reqId,
}));
}
else {
for (let i = 0; i < records.size(); i++) {
const record = records.get(i);
ranges.push({ begin: Number(record.begin), end: Number(record.end), requestId });
record.delete();
}
}
await this.downloadResourceRange(dataId, requestId, ranges, onProgress, signal);
}
/**
* Returns a list of references of the owner file/assembly.
*
* References are images, fonts, or any other files to correct rendering of the file.
*
* @param signal - An
* {@link https://developer.mozilla.org/docs/Web/API/AbortController | AbortController} signal, which
* can be used to abort waiting as desired.
*/
getReferences(signal) {
return this._file.getReferences(signal);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
function delay(ms, signal) {
return new Promise((resolve) => {
let timeoutId = 0;
const abortHandler = () => {
clearTimeout(timeoutId);
resolve(true);
};
timeoutId = window.setTimeout(() => {
signal.removeEventListener("abort", abortHandler);
resolve(false);
}, ms);
signal.addEventListener("abort", abortHandler, { once: true });
});
}
async function waitFor(func, params = {}) {
var _a, _b, _c;
const timeout = params.timeout || 600000;
const interval = params.interval || 3000;
const signal = (_a = params.signal) !== null && _a !== undefined ? _a : new AbortController().signal;
const abortError = (_b = params.abortError) !== null && _b !== undefined ? _b : new DOMException("Aborted", "AbortError");
const timeoutError = (_c = params.timeoutError) !== null && _c !== undefined ? _c : new DOMException("Timeout", "TimeoutError");
const end = performance.now() + timeout;
let count = timeout / interval;
do {
if (await func(params))
return Promise.resolve(params.result);
if ((await delay(interval, signal)) || signal.aborted)
return Promise.reject(abortError);
} while (performance.now() < end && --count > 0);
return Promise.reject(timeoutError);
}
function parseArgs(args) {
if (typeof args === "string") {
const firstArg = args.indexOf("--");
if (firstArg !== -1)
args = args.slice(firstArg);
const argArray = args
.split("--")
.map((x) => x
.split("=")
.map((y) => y.split(" "))
.flat())
.filter((x) => x[0])
.map((x) => x.concat([""]));
return Object.fromEntries(argArray);
}
return args || {};
}
function userFullName(firstName, lastName = "", userName = "") {
var _a;
if (firstName && typeof firstName !== "string") {
return userFullName((_a = firstName.firstName) !== null && _a !== undefined ? _a : firstName.name, firstName.lastName, firstName.userName);
}
return `${firstName !== null && firstName !== undefined ? firstName : ""} ${lastName !== null && lastName !== undefined ? lastName : ""}`.trim() || userName;
}
function userInitials(fullName = "") {
const names = fullName.split(" ").filter((x) => x);
return names
.reduce((initials, name, index) => {
if (index === 0 || index === names.length - 1)
initials += name.charAt(0);
return initials;
}, "")
.toUpperCase();
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a file/assembly clash detection test.
*/
class ClashTest extends Endpoint {
/**
* @param data - Raw test data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
* @param path - The clash test API path of the file/assembly that owns the test.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, path, httpClient) {
super(`${path}/clashes/${data.id}`, httpClient);
this.data = data;
}
/**
* The type of the clashes that the test detects:
*
* - `true` - Сlearance clash. A clash in which the object A may or may not intersect with object B, but
* comes within a distance of less than the {@link tolerance}.
* - `false` - Hard clash. A clash in which the object A intersects with object B by a distance of more
* than the {@link tolerance}.
*
* @readonly
*/
get clearance() {
return this.data.clearance;
}
/**
* Test creation time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get createdAt() {
return this.data.createdAt;
}
/**
* Raw test data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
this._data.owner.avatarUrl = `${this.httpClient.serverUrl}/users/${this._data.owner.userId}/avatar`;
this._data.owner.fullName = userFullName(this._data.owner);
this._data.owner.initials = userInitials(this._data.owner.fullName);
}
/**
* Unique test ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* Test last update (UTC) time in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get lastModifiedAt() {
return this.data.lastModifiedAt;
}
/**
* Test name.
*/
get name() {
return this.data.name;
}
set name(value) {
this.data.name = value;
}
/**
* Test owner information.
*
* @readonly
*/
get owner() {
return this.data.owner;
}
/**
* First selection set for clash detection. Objects from `selectionSetA` will be tested against each
* others by objects from the `selectionSetB` during the test.
*
* @readonly
*/
get selectionSetA() {
return this.data.selectionSetA;
}
/**
* The type of first selection set for clash detection. Can be one of:
*
* - `all` - All file/assembly objects.
* - `handle` - Objects with original handles specified in the `selectionSetA`.
* - `models` - All objects of the models with original handles specified in the `selectionSetA`.
* - `searchquery` - Objects retrieved by the search queries specified in `selectionSetA`.
*
* @readonly
*/
get selectionTypeA() {
return this.data.selectionTypeA;
}
/**
* Second selection set for clash detection. Objects from `selectionSetB` will be tested against each
* others by objects from the `selectionSetA` during the test.
*
* @readonly
*/
get selectionSetB() {
return this.data.selectionSetB;
}
/**
* The type of second selection set for clash detection. Can be one of:
*
* - `all` - All file/assembly objects.
* - `handle` - Objects with original handles specified in the `selectionSetB`.
* - `models` - All objects of the models with original handles specified in the `selectionSetB`.
* - `searchquery` - Objects retrieved by the search queries specified in `selectionSetB`.
*
* @readonly
*/
get selectionTypeB() {
return this.data.selectionTypeB;
}
/**
* Test status. Can be `none`, `waiting`, `inprogress`, `done` or `failed`.
*
* @readonly
*/
get status() {
return this.data.status;
}
/**
* The distance of separation between objects at which test begins detecting clashes.
*
* @readonly
*/
get tolerance() {
return this.data.tolerance;
}
/**
* Reloads test data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates test data on the server.
*
* @param data - Raw test data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes a test and its results report from the server.
*
* @returns Returns the raw data of a deleted test. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves test properties changes to the server. Call this method to update test data on the server
* after any property changes.
*/
save() {
return this.update(this.data);
}
/**
* Waits for test to complete. Test is done when it changes to `done` or `failed` status.
*
* @param params - An object containing waiting parameters.
* @param params.timeout - The time, in milliseconds that the function should wait test. If test is not
* complete during this time, the `TimeoutError` exception will be thrown.
* @param params.interval - The time, in milliseconds, the function should delay in between checking
* test 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.
*/
waitForDone(params) {
const checkDone = () => this.checkout().then((test) => {
var _a;
const ready = ["done", "failed"].includes(test.status);
const cancel = (_a = params === null || params === undefined ? undefined : params.onCheckout) === null || _a === undefined ? undefined : _a.call(params, test, ready);
return cancel || ready;
});
return waitFor(checkDone, params).then(() => this);
}
/**
* Returns a list of detected clashes for this test.
*/
getReport() {
return this.get("/report").then((response) => response.json());
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about an assembly on the Open Cloud Server
* and managing its data.
*/
class Assembly extends Endpoint {
/**
* @param data - Raw assembly data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, httpClient) {
super(`/assemblies/${data.id}`, httpClient);
this.data = data;
}
// Reserved for future use
get activeVersion() {
return this.data.activeVersion;
}
/**
* List of unique files from which the assembly was created.
*
* @readonly
*/
get associatedFiles() {
return this.data.associatedFiles;
}
/**
* Assembly creation time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get created() {
return this.data.created;
}
/**
* Returns the raw assembly data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
*/
get data() {
return this._data;
}
set data(value) {
var _a;
var _b;
this._data = value;
this._data.owner.avatarUrl = `${this.httpClient.serverUrl}/users/${this._data.owner.userId}/avatar`;
this._data.owner.fullName = userFullName(this._data.owner);
this._data.owner.initials = userInitials(this._data.owner.fullName);
// associatedFiles since 23.12
(_a = (_b = this._data).associatedFiles) !== null && _a !== undefined ? _a : (_b.associatedFiles = []);
this._data.associatedFiles.forEach((file) => (file.link = `${this.httpClient.serverUrl}/files/${file.fileId}`));
}
/**
* List of file IDs from which the assembly was created.
*
* @readonly
*/
get files() {
return this.data.files;
}
/**
* Assembly geometry data type:
*
* - `vsfx` - `VSFX` format, assembly can be opened in `VisualizeJS` 3D viewer.
*
* Returns an empty string if the geometry data is not yet ready.
*/
get geometryType() {
return this.status === "done" ? "vsfx" : "";
}
/**
* Unique assembly ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* Assembly name.
*/
get name() {
return this.data.name;
}
set name(value) {
this.data.name = value;
}
// Reserved for future use
get originalAssemblyId() {
return this.data.originalAssemblyId;
}
/**
* Assembly owner information.
*
* @readonly
*/
get owner() {
return this.data.owner;
}
// Reserved for future use
get previewUrl() {
return this.data.previewUrl || "";
}
/**
* List of assembly related job IDs.
*
* @readonly
*/
get relatedJobs() {
return this.data.relatedJobs;
}
/**
* Assembly geometry data and properties status. Can be `waiting`, `inprogress`, `done` or `failed`.
*
* An assemblies without geometry data cannot be opened in viewer.
*
* @readonly
*/
get status() {
return this.data.status;
}
/**
* Assembly type. Returns an `assembly` string.
*
* @readonly
*/
get type() {
return "assembly";
}
// Reserved for future use
get version() {
return this.data.version;
}
get versions() {
return this.data.versions;
}
/**
* Reloads assembly data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates assembly data on the server.
*
* @param data - Raw assembly data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes an assembly from the server.
*
* @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 Assemblies API}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves assembly properties changes to the server. Call this method to update assembly data on the
* server after any property changes.
*/
save() {
return this.update(this.data);
}
// Reserved for future use
setPreview(image) {
console.warn("Assembly does not support preview");
return Promise.resolve(this);
}
deletePreview() {
console.warn("Assembly does not support preview");
return Promise.resolve(this);
}
/**
* Returns list of assembly models.
*/
getModels() {
return this.get("/geometry")
.then((response) => response.json())
.then((array) => array.map((data) => new Model(data, this)));
}
/**
* Returns a model transformation.
*
* @param handle - Model original handle.
*/
getModelTransformMatrix(handle) {
return this.data.transform[handle];
}
/**
* Sets or removes a model transformation.
*
* @param handle - Model original handle.
* @param transform - Transformation matrix. Specify `undefined` to remove transformation.
*/
setModelTransformMatrix(handle, transform) {
const obj = { ...this.data.transform };
obj[handle] = transform;
return this.update({ transform: obj });
}
/**
* Object properties.
*
* @typedef {any} Properties
* @property {string} handle - Object original handle.
* @property {string | any} * - Object property. Can be `any` for nested group properties.
*/
/**
* Returns the properties for an objects in the assembly.
*
* @param handles - Object original handle or handles array. Specify `undefined` to get properties for
* all objects in the assembly.
* @param group - If the `group` parameter is `true`, properties are returned grouped by category. By
* default, or if `group` is set to `false`, properties are returned ungrouped.
*
* To get grouped properties, the `--properties_group` command line argument must be specified for the
* `properties` File Converter job when {@link Client.createAssembly | creating the assembly}.
*
* ```javascript
* await client.createAssembly([file1.id, file2.id], "AssemblyName", {
* jobParameters: { properties: "--properties_group" },
* waitForDone: true,
* });
* ```
*
* Otherwise, the properties will be returned ungrouped, even if the `group` is `true`.
*/
getProperties(handles, group = false) {
const searchParams = new URLSearchParams();
if (handles) {
if (Array.isArray(handles))
handles = handles.join(",");
if (typeof handles === "string")
handles = handles.trim();
if (handles)
searchParams.set("handles", handles);
}
if (group)
searchParams.set("group", "true");
let queryString = searchParams.toString();
if (queryString)
queryString = "?" + queryString;
return this.get(`/properties${queryString}`).then((response) => response.json());
}
/**
* Returns the list of original handles for an objects in the file that match the specified patterns.
* Search patterns may be combined using query operators.
*
* @example Simple search pattern.
*
* ```javascript
* searchPattern = {
* key: "Category",
* value: "OST_Stairs",
* };
* ```
*
* @example Search patterns combination.
*
* ```javascript
* searchPattern = {
* $or: [
* {
* $and: [
* { key: "Category", value: "OST_GenericModel" },
* { key: "Level", value: "03 - Floor" },
* ],
* },
* { key: "Category", value: "OST_Stairs" },
* ],
* };
* ```
*
* @param searchPattern - Search pattern or combination of the patterns, see example below.
*/
searchProperties(searchPattern) {
return this.post("/properties/search", searchPattern).then((response) => response.json());
}
/**
* Returns the CDA tree for an assembly.
*/
getCdaTree() {
return this.get(`/properties/tree`).then((response) => response.json());
}
/**
* Returns a list of assembly viewpoints. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#AssemblyViewpoints | Open Cloud Assembly Viewpoints API}.
*/
getViewpoints() {
return this.get("/viewpoints")
.then((response) => response.json())
.then((viewpoints) => viewpoints.result);
}
/**
* Saves a new assembly viewpoint to the server. To create a viewpoint use `Viewer.createViewpoint()`.
*
* @param viewpoint - Viewpoint object. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#AssemblyViewpoints | Open Cloud Assembly Viewpoints API}.
*/
saveViewpoint(viewpoint) {
return this.post("/viewpoints", viewpoint).then((response) => response.json());
}
/**
* Deletes the specified assembly viewpoint.
*
* @param guid - Viewpoint GUID.
* @returns Returns a deleted viewpoint. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#AssemblyViewpoints | Open Cloud Assembly Viewpoints API}.
*/
deleteViewpoint(guid) {
return super.delete(`/viewpoints/${guid}`).then((response) => response.json());
}
/**
* Returns the viewpoint snapshot as base64-encoded
* {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL}.
*
* @param guid - Viewpoint GUID.
*/
getSnapshot(guid) {
return this.get(`/viewpoints/${guid}/snapshot`).then((response) => response.text());
}
/**
* Returns the viewpoint snapshot data.
*
* @param guid - Viewpoint GUID.
* @param bitmapGuid - Bitmap GUID.
*/
getSnapshotData(guid, bitmapGuid) {
return this.get(`/viewpoints/${guid}/bitmaps/${bitmapGuid}`).then((response) => response.text());
}
/**
* Downloads an assembly resource file. Resource files are files that contain model scene descriptions,
* or geometry data.
*
* @param dataId - Resource file name.
* @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.
*/
downloadResource(dataId, onProgress, signal) {
return this.httpClient
.downloadFile(this.getEndpointPath(`/downloads/${dataId}`), onProgress, { signal, headers: this.headers })
.then((response) => response.arrayBuffer());
}
/**
* Downloads a part of assembly resource file. Resource files are files that contain model scene
* descriptions, or geometry data.
*
* @param dataId - Resource file name.
* @param ranges - A ranges of resource file contents to download. See
* {@link https://developer.mozilla.org/docs/Web/HTTP/Guides/Range_requests | HTTP range requests} for
* more details.
* @param requestId - Specify a non-empty `requestId` to append the `?requestId=` search parameter to
* the server request. If specified, server-side caching may not work.
* @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.
*/
downloadResourceRange(dataId, requestId, ranges, onProgress, signal) {
return this.httpClient
.downloadFileRange(this.getEndpointPath(`/downloads/${dataId}${requestId ? "?requestId=" + requestId : ""}`), requestId, ranges, onProgress, { signal, headers: this.headers })
.then((response) => response.arrayBuffer());
}
/**
* Deprecated since `25.3`. Use {@link downloadResource | downloadResource()} instead.
*
* @deprecated
*/
partialDownloadResource(dataId, onProgress, signal) {
console.warn("Assembly.partialDownloadResource() has been deprecated since 25.3 and will be removed in a future release, use Assembly.downloadResource() instead.");
return this.downloadResource(dataId, onProgress, signal);
}
/**
* Deprecated since `25.3`. Use {@link downloadResourceRange | downloadResourceRange()} instead.
*/
async downloadFileRange(requestId, records, dataId, onProgress, signal) {
await this.downloadResourceRange(dataId, requestId, records, onProgress, signal);
}
/**
* Returns a list of assembly references containing references from all the files from which the
* assembly was created.
*
* References are images, fonts, or any other files to correct rendering of the assembly.
*
* @param signal - An
* {@link https://developer.mozilla.org/docs/Web/API/AbortController | AbortController} signal, which
* can be used to abort waiting as desired.
*/
async getReferences(signal) {
const files = new Endpoint("/files", this.httpClient, this.headers);
const references = await Promise.all(this.associatedFiles
.map((file) => `/${file.fileId}/references`)
.map((link) => files.get(link, signal).then((response) => response.json())))
.then((references) => references.map((x) => x.references))
.then((references) => references.reduce((x, v) => [...v, ...x], []))
.then((references) => [...new Set(references.map(JSON.stringify))].map((x) => JSON.parse(x)));
return { id: "", references };
}
/**
* Waits for assembly to be created. Assembly is created when it changes to `done` or `failed` status.
*
* @param params - An object containing waiting parameters.
* @param params.timeout - The time, in milliseconds that the function should wait assembly. If
* assembly is not created during this time, the `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.
*/
waitForDone(params) {
const checkDone = () => this.checkout().then((assembly) => {
var _a;
const ready = ["done", "failed"].includes(assembly.status);
const cancel = (_a = params === null || params === undefined ? undefined : params.onCheckout) === null || _a === undefined ? undefined : _a.call(params, assembly, ready);
return cancel || ready;
});
return waitFor(checkDone, params).then(() => this);
}
/**
* Returns a list of assembly clash tests.
*
* @param start - The starting index in the test list. Used for paging.
* @param limit - The maximum number of tests that should be returned per request. Used for paging.
* @param name - Filter the tests by part of the name. Case sensitive.
* @param ids - List of tests IDs to return.
* @param sortByDesc - Allows to specify the descending order of the result. By default tests are
* sorted by name in ascending order.
* @param sortField - Allows to specify sort field.
*/
getClashTests(start, limit, name, ids, sortByDesc, sortField) {
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.get(`/clashes${queryString}`)
.then((response) => response.json())
.then((tests) => {
return {
...tests,
result: tests.result.map((data) => new ClashTest(data, this.path, this.httpClient)),
};
});
}
/**
* Returns information about the specified assembly clash test.
*
* @param testId - Test ID.
*/
getClashTest(testId) {
return this.get(`/clashes/${testId}`)
.then((response) => response.json())
.then((data) => new ClashTest(data, this.path, this.httpClient));
}
/**
* Creates an assembly clash test. Assembly must be in a `done` state, otherwise the test will fail.
*
* @param name - Test name.
* @param selectionTypeA - The type of first selection set for clash detection. Can be one of:
*
* - `all` - All file/assembly objects.
* - `handle` - Objects with original handles specified in the `selectionSetA`.
* - `models` - All objects of the models with original handles specified in the `selectionSetA`.
* - `searchquery` - Objects retrieved by the search queries specified in `selectionSetA`.
*
* @param selectionTypeB - The type of second selection set for clash detection. Can be one of:
*
* - `all` - All file/assembly objects.
* - `handle` - Objects with original handles specified in the `selectionSetB`.
* - `models` - All objects of the models with original handles specified in the `selectionSetB`.
* - `searchquery` - Objects retrieved by the search queries specified in `selectionSetB`.
*
* @param selectionSetA - First selection set for clash detection. Objects from `selectionSetA` will be
* tested against each others by objects from the `selectionSetB` during the test.
* @param selectionSetB - Second selection set for clash detection. Objects from `selectionSetB` will
* be tested against each others by objects from the `selectionSetA` during the test.
* @param params - An object containing test parameters.
* @param params.tolerance - The distance of separation between objects at which test begins detecting
* clashes.
* @param params.clearance - The type of the clashes that the test detects:
*
* - `true` - Сlearance clash. A clash in which the object A may or may not intersect with object B, but
* comes within a distance of less than the `tolerance`.
* - `false` - Hard clash. A clash in which the object A intersects with object B by a distance of more
* than the `tolerance`.
*
* @param params.waitForDone - Wait for test to complete.
* @param params.timeout - The time, in milliseconds that the function should wait test. If test is not
* complete during this time, the `TimeoutError` exception will be thrown.
* @param params.interval - The time, in milliseconds, the function should delay in between checking
* test 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.
*/
createClashTest(name, selectionTypeA, selectionTypeB, selectionSetA, selectionSetB, params) {
const { tolerance, clearance, waitForDone } = params !== null && params !== undefined ? params : {};
if (!Array.isArray(selectionSetA))
selectionSetA = [selectionSetA];
if (!Array.isArray(selectionSetB))
selectionSetB = [selectionSetB];
return this.post("/clashes", {
name,
selectionTypeA,
selectionTypeB,
selectionSetA,
selectionSetB,
tolerance,
clearance,
})
.then((response) => response.json())
.then((data) => new ClashTest(data, this.path, this.httpClient))
.then((result) => (waitForDone ? result.waitForDone(params) : result));
}
/**
* Deletes the specified assembly clash test.
*
* @param testId - Test ID.
* @returns Returns the raw data of a deleted test. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Assemblies | Open Cloud Assemblies API}.
*/
deleteClashTest(testId) {
return super.delete(`/clashes/${testId}`).then((response) => response.json());
}
// Reserved for future use
updateVersion(files, params = {
waitForDone: false,
}) {
return Promise.reject(new Error("Assembly version support will be implemeted in a future release"));
}
getVersions() {
return Promise.resolve(undefined);
}
getVersion(version) {
return Promise.reject(new FetchError(404));
}
deleteVersion(version) {
return Promise.reject(new FetchError(404));
}
setActiveVersion(version) {
return this.update({ activeVersion: version });
}
// Reserved for future use
createSharedLink(permissions) {
return Promise.reject(new Error("Assembly shared link will be implemeted in a future release"));
}
getSharedLink() {
return Promise.resolve(undefined);
}
deleteSharedLink() {
return Promise.reject(new FetchError(404));
}
}
class EventEmitter2 {
constructor() {
this._listeners = {};
}
addEventListener(type, listener) {
if (this._listeners[type] === undefined) this._listeners[type] = [];
this._listeners[type].push(listener);
return this;
}
removeEventListener(type, listener) {
if (this._listeners[type] === undefined) return this;
const listeners = this._listeners[type].filter((x => x !== listener));
if (listeners.length !== 0) this._listeners[type] = listeners; else delete this._listeners[type];
return this;
}
removeAllListeners(type) {
if (type) delete this._listeners[type]; else this._listeners = {};
return this;
}
emitEvent(event) {
if (this._listeners[event.type] === undefined) return false;
const invoke = this._listeners[event.type].slice();
invoke.forEach((listener => listener.call(this, event)));
return true;
}
on(type, listener) {
return this.addEventListener(type, listener);
}
off(type, listener) {
return this.removeEventListener(type, listener);
}
emit(type, ...args) {
if (typeof type === "string") return this.emitEvent({
type: type,
args: args
}); else if (typeof type === "object") return this.emitEvent(type); else return false;
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
function handleFetchError(response) {
if (!response.ok) {
switch (response.status) {
case 400: {
return response.text().then((text) => {
console.error(text);
return Promise.reject(new FetchError(400, error400(text)));
});
}
case 500: {
return response.text().then((text) => {
console.error(error400(text, text));
return Promise.reject(new FetchError(500));
});
}
default:
return Promise.reject(new FetchError(response.status));
}
}
return Promise.resolve(response);
}
function $fetch(url, init = { method: "GET" }) {
const headers = { ...init.headers };
delete headers["Content-Type"];
Object.keys(headers)
.filter((x) => headers[x] === undefined)
.forEach((x) => delete headers[x]);
let body = undefined;
if (init.method === "POST" || init.method === "PUT") {
if (init.body instanceof FormData) {
body = init.body;
}
else if (init.body instanceof Blob) {
body = new FormData();
body.append("file", init.body);
}
else if (init.body instanceof ArrayBuffer) {
body = new FormData();
body.append("file", new Blob([init.body]));
}
else if (typeof init.body === "object") {
body = JSON.stringify(init.body);
headers["Content-Type"] = "application/json";
}
else if (typeof init.body === "string") {
body = init.body;
headers["Content-Type"] = "text/plain";
}
}
return fetch(url, { ...init, headers, body }).then(handleFetchError);
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
function handleXMLHttpError(xhr) {
if (xhr.status === 0) {
return Promise.reject(new FetchError(0, "Network error"));
}
if (xhr.status < 200 || xhr.status > 299) {
switch (xhr.status) {
case 400: {
console.error(xhr.responseText);
return Promise.reject(new FetchError(400, error400(xhr.responseText)));
}
case 500: {
console.error(error400(xhr.responseText, xhr.responseText));
return Promise.reject(new FetchError(500));
}
default: {
return Promise.reject(new FetchError(xhr.status));
}
}
}
return Promise.resolve(xhr);
}
function $xmlhttp(url, params = { method: "GET" }) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(params.method, url, true);
for (const key in params.headers) {
xhr.setRequestHeader(key, params.headers[key]);
}
function calcProgress(event) {
return event.lengthComputable ? event.loaded / event.total : 1;
}
xhr.upload.onprogress = (event) => params.uploadProgress && params.uploadProgress(calcProgress(event));
xhr.onprogress = (event) => params.downloadProgress && params.downloadProgress(calcProgress(event));
xhr.onloadend = (event) => handleXMLHttpError(event.target).then(resolve, reject);
xhr.send(params.body);
});
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
class HttpClient {
constructor(serverUrl) {
this.headers = {};
this.signInUserId = "";
this.signInUserIsAdmin = false;
this.serverUrl = serverUrl;
}
get(relativePath, init = {}) {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "GET",
headers: { ...this.headers, ...init.headers },
});
}
post(relativePath, body, init = {}) {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "POST",
headers: { ...this.headers, ...init.headers },
body,
});
}
put(relativePath, body, init = {}) {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "PUT",
headers: { ...this.headers, ...init.headers },
body,
});
}
delete(relativePath, init = {}) {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "DELETE",
headers: { ...this.headers, ...init.headers },
});
}
uploadFile(relativePath, file, onProgress, init = {}) {
const data = new FormData();
data.append("file", file);
return $xmlhttp(`${this.serverUrl}${relativePath}`, {
method: "POST",
headers: { ...this.headers, ...init.headers },
body: data,
uploadProgress: onProgress,
});
}
async downloadFile(relativePath, onProgress, init = {}) {
const response = await this.get(relativePath, init);
if (!onProgress)
return response;
const contentLength = response.headers.get("Content-Length");
const total = parseInt(contentLength || "", 10) || 1;
const stream = new ReadableStream({
async start(controller) {
const reader = response.body.getReader();
let loaded = 0;
while (true) {
const { done, value } = await reader.read();
if (done)
break;
controller.enqueue(value);
loaded += value.length;
onProgress(loaded / total, value);
}
controller.close();
},
});
return new Response(stream);
}
async downloadFileRange(relativePath, reserved, ranges, onProgress, init = {}) {
const headers = {
...init.headers,
Range: "bytes=" + ranges.map((x) => `${x.begin}-${x.end}`).join(","),
};
const response = await this.get(relativePath, { ...init, headers });
if (!onProgress)
return response;
const contentLength = response.headers.get("content-length");
const total = parseInt(contentLength || "", 10) || 1;
const stream = new ReadableStream({
async start(controller) {
const reader = response.body.getReader();
let loaded = 0;
let rangedIndex = 0;
let rangePos = 0;
while (true) {
const { done, value } = await reader.read();
if (done)
break;
controller.enqueue(value);
loaded += value.length;
let chunkLeft = value.length;
let chunkPos = 0;
while (chunkLeft > 0) {
const range = ranges[rangedIndex];
const rangeLeft = range.end - range.begin + 1 - rangePos;
if (chunkLeft < rangeLeft) {
const chunk = value.subarray(chunkPos, chunkPos + chunkLeft);
onProgress(loaded / total, chunk, range.requestId);
rangePos += chunkLeft;
chunkLeft = 0;
}
else {
const chunk = value.subarray(chunkPos, chunkPos + rangeLeft);
onProgress(loaded / total, chunk, range.requestId);
chunkPos += rangeLeft;
chunkLeft -= rangeLeft;
rangedIndex++;
rangePos = 0;
}
}
}
controller.close();
},
});
return new Response(stream);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about {@link File | file} actions granted to
* a specific user, project, or group.
*/
class Permission extends Endpoint {
/**
* @param data - Raw permission data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Permission | Open Cloud Permissions API}.
* @param fileId - Owner file ID.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, fileId, httpClient) {
super(`/files/${fileId}/permissions/${data.id}`, httpClient);
this.data = data;
}
/**
* Defines what actions are allowed to be performed on a file with this permission:
*
* - `read` - The ability to read file description, geometry data and properties.
* - `readSourceFile` - The ability to download source file.
* - `write` - The ability to modify file name, description and references.
* - `readViewpoint` - The ability to read file viewpoints.
* - `createViewpoint` - The ability to create file viewpoints.
*
* @example Change file permissions for the the specified project.
*
* ```javascript
* const myFile = client.getFile(myFileId);
* const permissions = await myFile.getPermissions();
* const projectPermissions = permissions.filter((permission) =>
* permission.grantedTo.some((x) => x.project?.id === myProjectId)
* );
* const newActions = ["read", "readSourceFile", "update"];
* await Promise.all(
* projectPermissions.map((permission) => {
* permission.actions = newActions;
* return permission.save();
* })
* );
* ```
*/
get actions() {
return this.data.actions;
}
set actions(value) {
this._data.actions = value;
}
/**
* Raw permission data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Permission | Open Cloud Permissions API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
}
/**
* Unique permission ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* A list of users, projects, or groups that will get access to the file.
*/
get grantedTo() {
return this.data.grantedTo;
}
set grantedTo(value) {
this.data.grantedTo = value;
}
/**
* Specifies whether all users have access to the file or not.
*/
get public() {
return this.data.public;
}
set public(value) {
this.data.public = value;
}
/**
* Reloads permission data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates permission data on the server.
*
* @param data - Raw permission data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Permission | Open Cloud Permissions API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Removes a permission from the file.
*
* @returns Returns the raw data of a deleted permission. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Permission | Open Cloud Permissions API}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves permission properties changes to the server. Call this method to update permission data on the
* server after any property changes.
*/
save() {
return this.update(this.data);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a job on the Open Cloud Server.
*/
class Job extends Endpoint {
/**
* @param data - Raw job data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Jobs | Open Cloud Jobs API}.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, httpClient) {
super(`/jobs/${data.id}`, httpClient);
this.data = data;
}
/**
* The ID of the assembly the job is working on (internal).
*
* @readonly
*/
get assemblyId() {
return this.data.assemblyId;
}
/**
* Job creator ID. Use {@link Client.getUser | Client.getUser()} to obtain detailed creator information.
*
* @readonly
*/
get authorId() {
return this.data.authorId;
}
/**
* Job creation time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get createdAt() {
return this.data.createdAt;
}
/**
* Raw job data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Jobs | Open Cloud Jobs API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
}
/**
* `true` if job is `done` or `failed`. See {@link status} for more details.
*
* @readonly
*/
get done() {
return this.data.status === "done" || this.data.status === "failed";
}
/**
* The ID of the file the job is working on.
*
* @readonly
*/
get fileId() {
return this.data.fileId;
}
/**
* Unique job ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* Job last update (UTC) time in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get lastUpdate() {
return this.data.lastUpdate;
}
/**
* Job type. Can be:
*
* - `geometry` - Convert file geometry data to `VSFX` format.
* - `geometryGltf` - Convert file geometry data to `glTF` format.
* - `properties` - Extract file properties.
* - `validation` - Validate the IFC file.
* - `clash` - Create the clash detection report.
* - `dwg`, `obj`, `gltf`, `glb`, `vsf`, `pdf`, `3dpdf` - Export file to the specified format.
* - Other custom job name.
*
* @readonly
*/
get outputFormat() {
return this.data.outputFormat;
}
/**
* Parameters with which the job was started. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Jobs | Open Cloud Jobs API}.
*
* @readonly
*/
get parameters() {
return this.data.parameters;
}
/**
* Job status. Can be `waiting`, `inprogress`, `done` or `failed`.
*
* @readonly
*/
get status() {
return this.data.status;
}
/**
* Job status description message.
*
* @readonly
*/
get statusMessage() {
return this.data.statusMessage;
}
/**
* Job starting time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get startedAt() {
return this.data.startedAt;
}
/**
* Reloads job data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates job data on the server.
*
* Only administrators can update job data. If the current logged in user is not an administrator, an
* exception will be thrown.
*
* @param data - Raw job data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Jobs | Open Cloud Jobs API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes a job from the server job list. Jobs that are in progress or have already been completed
* cannot be deleted.
*
* @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}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
// /**
// * Save job properties changes to the server. Call this method to update job data on the server
// * after any property changes.
// */
// save() {
// return this.update(this.data);
// }
/**
* Waits for job to be done. Job is done when it changes to `done` or `failed` status.
*
* @param params - An object containing waiting parameters.
* @param params.timeout - The time, in milliseconds that the function should wait job. If jobs is not
* done during this time, the `TimeoutError` exception will be thrown.
* @param params.interval - The time, in milliseconds, the function should delay in between checking
* job 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.
*/
waitForDone(params) {
const checkDone = () => this.checkout().then((job) => {
var _a;
const ready = ["done", "failed"].includes(job.status);
const cancel = (_a = params === null || params === undefined ? undefined : params.onCheckout) === null || _a === undefined ? undefined : _a.call(params, job, ready);
return cancel || ready;
});
return waitFor(checkDone, params).then(() => this);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a file shared link.
*/
class SharedLink extends Endpoint {
/**
* @param data - Raw shared link data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#ShareLinks | Open Cloud SharedLinks API}.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, httpClient) {
super(`/shares/${data.token}`, httpClient);
this.data = data;
}
/**
* Shared link creation time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get createdAt() {
return this.data.createdAt;
}
/**
* Raw shared link data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#ShareLinks | Open Cloud SharedLinks API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
}
/**
* Share permissions.
*/
get permissions() {
return this.data.permissions;
}
set permissions(value) {
this.data.permissions = { ...this.data.permissions, ...value };
}
/**
* Unique shared link token.
*
* @readonly
*/
get token() {
return this.data.token;
}
/**
* URL to open shared file in the viewer.
*
* @readonly
*/
get url() {
return this.data.url;
}
/**
* Reloads shared link data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates shared link data on the server.
*
* @param data - Raw shared link data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#ShareLinks | Open Cloud SharedLinks API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes a shared link from the server.
*
* @returns Returns the raw data of a deleted shared link. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#SharedLinks | Open Cloud SharedLinks API}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves shared link properties changes to the server. Call this method to update shared link data on
* the server after any property changes.
*/
save() {
return this.update(this.data);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a file on the Open Cloud Server and
* managing its data and versions.
*/
class File extends Endpoint {
/**
* @param data - Raw file data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Files | Open Cloud Files API}.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, httpClient) {
super(`/files/${data.id}`, httpClient);
this.data = data;
}
/**
* Active version number of the file.
*
* @readonly
*/
get activeVersion() {
return this.data.activeVersion;
}
/**
* File creation time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get created() {
return this.data.created;
}
/**
* File custom fields object, to store custom data.
*/
get customFields() {
return this.data.customFields;
}
set customFields(value) {
this.data.customFields = value;
}
/**
* Raw file data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Files | Open Cloud Files API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
var _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
this._data = value;
this._data.previewUrl = value.preview
? `${this.httpClient.serverUrl}${this.path}/preview?updated=${value.updatedAt}`
: "";
// owner since 24.8
if (typeof this._data.owner === "string")
this._data.owner = { userId: this._data.owner };
(_a = (_p = this._data).owner) !== null && _a !== undefined ? _a : (_p.owner = {});
this._data.owner.avatarUrl = `${this.httpClient.serverUrl}/users/${this._data.owner.userId}/avatar`;
this._data.owner.fullName = userFullName(this._data.owner);
this._data.owner.initials = userInitials(this._data.owner.fullName);
// status since 24.9
(_b = (_q = this._data).status) !== null && _b !== undefined ? _b : (_q.status = {});
(_c = (_r = this._data.status).geometry) !== null && _c !== undefined ? _c : (_r.geometry = { state: (_d = this._data.geometryStatus) !== null && _d !== undefined ? _d : "none" });
(_e = (_s = this._data.status).properties) !== null && _e !== undefined ? _e : (_s.properties = { state: (_f = this._data.propertiesStatus) !== null && _f !== undefined ? _f : "none" });
(_g = (_t = this._data.status).validation) !== null && _g !== undefined ? _g : (_t.validation = { state: (_h = this._data.validationStatus) !== null && _h !== undefined ? _h : "none" });
// updatedBy since 24.10
(_j = (_u = this._data).updatedBy) !== null && _j !== undefined ? _j : (_u.updatedBy = {});
this._data.updatedBy.avatarUrl = `${this.httpClient.serverUrl}/users/${this._data.updatedBy.userId}/avatar`;
this._data.updatedBy.fullName = userFullName(this._data.updatedBy);
this._data.updatedBy.initials = userInitials(this._data.updatedBy.fullName);
// versions since 24.10
(_k = (_v = this._data).versions) !== null && _k !== undefined ? _k : (_v.versions = [{ ...value }]);
// geometryGltf status since 24.12
(_l = (_w = this._data.status).geometryGltf) !== null && _l !== undefined ? _l : (_w.geometryGltf = { state: "none" });
// isFileDeleted since 25.7
(_m = (_x = this._data).isFileDeleted) !== null && _m !== undefined ? _m : (_x.isFileDeleted = false);
// sharedLinkToken since 26.0
(_o = (_y = this._data).sharedLinkToken) !== null && _o !== undefined ? _o : (_y.sharedLinkToken = null);
}
/**
* Returns a list of file formats in which the active version of the file was exported.
*
* To export file to one of the supported formats run the File Converter job using
* {@link createJob | createJob()}. To download exported file use
* {@link downloadResource | downloadResource()}.
*
* For an example of exporting files to other formats, see the {@link downloadResource} help.
*
* @readonly
*/
get exports() {
return this.data.exports;
}
/**
* Geometry data type of the active file version. Can be one of:
*
* - `vsfx` - `VSFX` format, file can be opened in `VisualizeJS` 3D viewer.
* - `gltf` - `glTF` format, file can be opened in `Three.js` 3D viewer.
*
* Returns an empty string if geometry data has not yet been converted. A files without geometry data
* can be exported to other formas, but cannot be opened in viewer.
*/
get geometryType() {
if (this.status.geometryGltf.state === "done")
return "gltf";
else if (this.status.geometry.state === "done")
return "vsfx";
else
return "";
}
/**
* Unique file ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* Returns `true` if the source file of the active file version has been deleted.
*
* A files with deleted source file can be opened in the viewer, but cannot be exported to other
* formats.
*
* @readonly
*/
get isFileDeleted() {
return this.data.isFileDeleted;
}
/**
* File name, including the extension.
*/
get name() {
return this.data.name;
}
set name(value) {
this.data.name = value;
}
/**
* If the file is a version, then returns the ID of the original file. Otherwise, returns the file ID.
*
* @readonly
*/
get originalFileId() {
return this.data.originalFileId;
}
/**
* File owner information.
*
* @readonly
*/
get owner() {
return this.data.owner;
}
/**
* File preview image URL or empty string if the file does not have a preview. Use
* {@link setPreview | setPreview()} to change preview image.
*
* @readonly
*/
get previewUrl() {
return this.data.previewUrl;
}
/**
* The size of the active version of the file in bytes.
*
* @readonly
*/
get size() {
return this.data.size;
}
/**
* Total size of all versions of the file in bytes.
*
* @readonly
*/
get sizeTotal() {
return this.data.sizeTotal;
}
/**
* File shared link token or `null` if file is not shared yet.
*
* @readonly
*/
get sharedLinkToken() {
return this.data.sharedLinkToken;
}
/**
* Data status of the active version of the file. Contains:
*
* - `geometry` - status of geometry data of `vsfx` type.
* - `geometryGltf` - status of geometry data of `gltf` type.
* - `properties` - status of properties.
* - `validation` - status of validation.
*
* Each status entity is a record with properties:
*
* - `state` - Data state. Can be `none`, `waiting`, `inprogress`, `done` or `failed`.
* - `jobId` - Unique ID of the data job.
*
* @readonly
*/
get status() {
return this.data.status;
}
/**
* File type, matches the file extension (includes dot).
*
* @readonly
*/
get type() {
return this.data.type;
}
/**
* File last update time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get updatedAt() {
return this.data.updatedAt;
}
/**
* Information about the user who made the last update.
*
* @readonly
*/
get updatedBy() {
return this.data.updatedBy;
}
/**
* Zero-based file version number for version files. The original file has version `0`.
*/
get version() {
return this.data.version;
}
/**
* List of the file versions.
*
* @readonly
*/
get versions() {
return this.data.versions;
}
/**
* Reloads file data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates file data on the server.
*
* @param data - Raw file data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Files | Open Cloud Files API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes a file and all its versions from the server.
*
* You cannot delete a version file using `delete()`, only the original file. To delete a version file
* use {@link deleteVersion | deleteVersion()}.
*
* @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}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves file properties changes to the server. Call this method to update file data on the server
* after any property changes.
*/
save() {
return this.update(this.data);
}
/**
* Sets or removes the file preview.
*
* @param image - Preview image. Can be a
* {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL} string,
* {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer},
* {@link https://developer.mozilla.org/docs/Web/API/Blob/Blob | Blob} or
* {@link https://developer.mozilla.org/docs/Web/API/File | Web API File} object. Setting the `image`
* to `null` will remove the preview.
*/
async setPreview(image) {
if (!image) {
await this.deletePreview();
}
else {
const response = await this.post("/preview", image);
this.data = await response.json();
}
return this;
}
/**
* Removes the file preview.
*/
async deletePreview() {
const response = await super.delete("/preview");
this.data = await response.json();
return this;
}
/**
* Returns a list of models of the active version of the file.
*/
getModels() {
return this.get("/geometry")
.then((response) => response.json())
.then((array) => array.map((data) => new Model(data, this)));
}
// File does not support model transformation.
getModelTransformMatrix(handle) {
return undefined;
}
setModelTransformMatrix(handle, transform) {
console.warn("File does not support model transformation");
return Promise.resolve(this);
}
/**
* Object properties.
*
* @typedef {any} Properties
* @property {string} handle - Object original handle.
* @property {string | any} * - Object property. Can be `any` for nested group properties.
*/
/**
* Returns the properties for an objects in the active version of the file.
*
* @param handles - Object original handle or handles array. Specify `undefined` to get properties for
* all objects in the file.
* @param group - If the `group` parameter is `true`, properties are returned grouped by category. By
* default, or if `group` is set to `false`, properties are returned ungrouped.
*
* To get grouped properties, the `--properties_group` command line argument must be specified for the
* `properties` File Converter job when {@link Client.uploadFile | uploading the file}:
*
* ```javascript
* await client.uploadFile(file, {
* geometry: true,
* properties: true,
* jobParameters: { properties: "--properties_group" },
* waitForDone: true,
* });
* ```
*
* or when running the {@link extractProperties | extract file properties} job:
*
* ```javascript
* await file.extractProperties("--properties_group");
* ```
*
* Otherwise, the properties will be returned ungrouped, even if the `group` is `true`.
*/
getProperties(handles, group = false) {
const searchParams = new URLSearchParams();
if (handles) {
if (Array.isArray(handles))
handles = handles.join(",");
if (typeof handles === "string")
handles = handles.trim();
if (handles)
searchParams.set("handles", handles);
}
if (group)
searchParams.set("group", "true");
let queryString = searchParams.toString();
if (queryString)
queryString = "?" + queryString;
return this.get(`/properties${queryString}`).then((response) => response.json());
}
/**
* Search pattern.
*
* @typedef {any} SearchPattern
* @property {string} key - Property name.
* @property {string} value - Property value.
*/
/**
* Query operator. Operator name can be `$and`, `$or`, `$not`, `$eq`, `$regex`.
*
* @typedef {any} QueryOperator
* @property {string | SearchPattern[] | QueryOperator[]} * - Array of the query values or patterns for
* operator.
*/
/**
* Returns the list of original handles for an objects in the active version of the file that match the
* specified patterns. Search patterns may be combined using query operators.
*
* @example Simple search pattern.
*
* ```javascript
* searchPattern = {
* key: "Category",
* value: "OST_Stairs",
* };
* ```
*
* @example Search patterns combination.
*
* ```javascript
* searchPattern = {
* $or: [
* {
* $and: [
* { key: "Category", value: "OST_GenericModel" },
* { key: "Level", value: "03 - Floor" },
* ],
* },
* { key: "Category", value: "OST_Stairs" },
* ],
* };
* ```
*
* @param {SeacrhPattern | QueryOperator} searchPattern - Search pattern or combination of the
* patterns, see example below.
* @returns {Promise<Properties[]>}
*/
searchProperties(searchPattern) {
return this.post("/properties/search", searchPattern).then((response) => response.json());
}
/**
* Returns the CDA tree for an active version of the file.
*/
getCdaTree() {
return this.get(`/properties/tree`).then((response) => response.json());
}
/**
* Returns a list of file viewpoints. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#FileViewpoints | Open Cloud File Viewpoints API}.
*/
getViewpoints() {
return this.get("/viewpoints")
.then((response) => response.json())
.then((viewpoints) => viewpoints.result);
}
/**
* Saves a new file viewpoint to the server. To create a viewpoint use `Viewer.createViewpoint()`.
*
* @param viewpoint - Viewpoint object. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#FileViewpoints | Open Cloud File Viewpoints API}.
*/
saveViewpoint(viewpoint) {
return this.post("/viewpoints", viewpoint).then((response) => response.json());
}
/**
* Deletes the specified file viewpoint.
*
* @param guid - Viewpoint GUID.
* @returns Returns the raw data of a deleted viewpoint. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#FileViewpoints | Open Cloud File Viewpoints API}.
*/
deleteViewpoint(guid) {
return super.delete(`/viewpoints/${guid}`).then((response) => response.json());
}
/**
* Returns viewpoint snapshot as base64-encoded
* {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL}.
*
* @param guid - Viewpoint GUID.
*/
getSnapshot(guid) {
return this.get(`/viewpoints/${guid}/snapshot`).then((response) => response.text());
}
/**
* Returns viewpoint snapshot data.
*
* @param guid - Viewpoint GUID.
* @param bitmapGuid - Bitmap GUID.
*/
getSnapshotData(guid, bitmapGuid) {
return this.get(`/viewpoints/${guid}/bitmaps/${bitmapGuid}`).then((response) => response.text());
}
/**
* Downloads the source file of active version of the file from the server.
*
* @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.
*/
download(onProgress, signal) {
return this.httpClient
.downloadFile(this.getEndpointPath("/downloads"), onProgress, { signal, headers: this.headers })
.then((response) => response.arrayBuffer());
}
/**
* Downloads a resource file of the active version of the file. Resource files are files that contain
* model scene descriptions, or geometry data, or exported files.
*
* @example Export file to PDF.
*
* ```javascript
* const job = await file.createJob("pdf");
* await job.waitForDone();
* const pdfResourceName = file.exports.find((x) => x.endsWith(".pdf"));
* const arrayBuffer = await file.downloadResource(pdfResourceName);
* const blob = new Blob([arrayBuffer]);
* const fileName = file.name + ".pdf";
* FileSaver.saveAs(blob, fileName);
* ```
*
* @param dataId - Resource file name.
* @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.
*/
downloadResource(dataId, onProgress, signal) {
return this.httpClient
.downloadFile(this.getEndpointPath(`/downloads/${dataId}`), onProgress, { signal, headers: this.headers })
.then((response) => response.arrayBuffer());
}
/**
* Downloads a part of resource file of the active version of the file. Resource files are files that
* contain model scene descriptions, or geometry data, or exported files.
*
* @param dataId - Resource file name.
* @param ranges - A ranges of resource file contents to download. See
* {@link https://developer.mozilla.org/docs/Web/HTTP/Guides/Range_requests | HTTP range requests} for
* more details.
* @param requestId - Specify a non-empty `requestId` to append the `?requestId=` search parameter to
* the server request. If specified, server-side caching may not work.
* @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.
*/
downloadResourceRange(dataId, requestId, ranges, onProgress, signal) {
return this.httpClient
.downloadFileRange(this.getEndpointPath(`/downloads/${dataId}${requestId ? "?requestId=" + requestId : ""}`), requestId, ranges, onProgress, { signal, headers: this.headers })
.then((response) => response.arrayBuffer());
}
/**
* Deprecated since `25.3`. Use {@link downloadResource | downloadResource()} instead.
*
* @deprecated
*/
partialDownloadResource(dataId, onProgress, signal) {
console.warn("File.partialDownloadResource() has been deprecated since 25.3 and will be removed in a future release, use File.downloadResource() instead.");
return this.downloadResource(dataId, onProgress, signal);
}
/**
* Deprecated since `25.3`. Use {@link downloadResourceRange | downloadResourceRange()} instead.
*
* @deprecated
*/
async downloadFileRange(requestId, records, dataId, onProgress, signal) {
await this.downloadResourceRange(dataId, requestId, records, onProgress, signal);
}
/**
* Returns a list of file references.
*
* References are images, fonts, or any other files to correct rendering of the file.
*
* @param signal - An
* {@link https://developer.mozilla.org/docs/Web/API/AbortController | AbortController} signal, which
* can be used to abort waiting as desired.
*/
getReferences(signal) {
return this.get("/references", signal).then((response) => response.json());
}
/**
* Sets the file references.
*
* References are images, fonts, or any other files to correct rendering of the file. Reference files
* must be uploaded to the server before they can be assigned to the current file.
*
* @param references - File references.
*/
setReferences(references) {
return this.put("/references", references).then((response) => response.json());
}
/**
* Runs a new job on the server for the active version of the file.
*
* @param outputFormat - The job type. Can be:
*
* - `geometry` - Convert file geometry data to `VSFX` format for opening in `VisualizeJS` 3D viewer.
* - `geometryGltf` - Convert file geometry data to `glTF` format for opening in `Three.js` 3D viewer.
* - `properties` - Extract file properties.
* - `validation` - Validate the IFC file.
* - `dwg`, `obj`, `gltf`, `glb`, `vsf`, `pdf`, `3dpdf` - Export file to the specified format. Use
* {@link exports} to get the list of completed file exports. Use
* {@link downloadResource | downloadResource()} to download the exported file.
* - Other custom job name. Custom job must be registered in the job templates before running.
*
* @param parameters - Parameters for the File Converter jobs or custom job. Can be given as command
* line arguments in form `--arg=value`.
*/
createJob(outputFormat, parameters) {
const jobs = new Endpoint("/jobs", this.httpClient, this.headers);
return jobs
.post(this.appendVersionParam(""), {
fileId: this.id,
outputFormat,
parameters: parseArgs(parameters),
})
.then((response) => response.json())
.then((data) => new Job(data, this.httpClient));
}
/**
* Runs a File Converter job to convert geometry data of active version of the file to the specified
* format. This is alias to {@link createJob | createJob("geometry")}.
*
* @param type - Geometry data type. Can be one of:
*
* - `vsfx` - `VSFX` format (default), for opening a file in `VisualizeJS` 3D viewer.
* - `gltf` - `glTF` format, for opening a file in `Three.js` 3D viewer.
*
* @param parameters - Parameters for the File Converter job. Can be given as command line arguments in
* form `--arg=value`.
*/
extractGeometry(type, parameters) {
return this.createJob(type === "gltf" ? "geometryGltf" : "geometry", parameters);
}
/**
* Runs a File Converter job to extract properties of the active version of the file. This is alias to
* {@link createJob | createJob("properties")}.
*
* @param parameters - Parameters for the File Converter job. Can be given as command line arguments in
* form `--arg=value`.
*/
extractProperties(parameters) {
return this.createJob("properties", parameters);
}
/**
* Runs an IFC validator job to validate the active version of the file. This is alias to
* {@link createJob | createJob("validation")}.
*
* To get validation report use {@link downloadResource | downloadResource("validation_report.json")}.
*
* @param parameters - Parameters for the IFC validator tool. Can be given as command line arguments in
* form `--arg=value`.
*/
validate(parameters) {
return this.createJob("validation", parameters);
}
/**
* Waits for jobs of the active version of the file to be done. Job is done when it changes to `none`,
* `done` or `failed` status.
*
* @param jobs - Job name or array of job names to wait on. Can be `geometry`, `geometryGltf`,
* `properties`, `validation`, `dwg`, `obj`, `gltf`, `glb`, `vsf`, `pdf`, `3dpdf` or custom job
* name.
* @param waitAll - If this parameter is `true`, the function returns when all the specified jobs have
* done. If `false`, the function returns when any one of the jobs are done.
* @param params - An object containing waiting parameters.
* @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.onCheckout - Waiting progress callback. Return `true` to cancel waiting.
*/
waitForDone(jobs, waitAll, params) {
const waitJobs = Array.isArray(jobs) ? jobs : [jobs];
if (waitAll === undefined)
waitAll = true;
const checkDone = () => this.checkout().then((file) => {
var _a;
const readyJobs = waitJobs.filter((job) => {
const jobStatus = file.status[job] || {};
return ["none", "done", "failed"].includes(jobStatus.state || "none");
});
const ready = waitAll ? readyJobs.length === waitJobs.length : readyJobs.length > 0;
const cancel = (_a = params === null || params === undefined ? undefined : params.onCheckout) === null || _a === undefined ? undefined : _a.call(params, file, ready);
return cancel || ready;
});
return waitFor(checkDone, params).then(() => this);
}
/**
* Returns a list of file permissions.
*/
getPermissions() {
return this.get("/permissions")
.then((response) => response.json())
.then((array) => array.map((data) => new Permission(data, this.id, this.httpClient)));
}
/**
* Returns information about specified file permission.
*
* @param permissionId - Permission ID.
*/
getPermission(permissionId) {
return this.get(`/permissions/${permissionId}`)
.then((response) => response.json())
.then((data) => new Permission(data, this.id, this.httpClient));
}
/**
* Creates a new file permission for a user, project, or group.
*
* @example Grant the specified user permission to "update" the file.
*
* ```javascript
* const action = "update";
* const grantedTo = [{ user: { id: myUser.id, email: myUser.email } }];
* await file.createPermission(action, grantedTo);
* ```
*
* @example Add a file to the specified project in "read-only" mode.
*
* ```javascript
* const actions = ["read", "readSourceFile"];
* const grantedTo = [{ project: { id: myProject.id, name: myProject.name } }];
* await file.createPermission(actions, grantedTo);
* ```
*
* @param actions - Actions are allowed to be performed on a file with this permission:
*
* - `read` - The ability to read file description, geometry data and properties.
* - `readSourceFile` - The ability to download source file.
* - `write` - The ability to modify file name, description and references.
* - `readViewpoint` - The ability to read file viewpoints.
* - `createViewpoint` - The ability to create file viewpoints.
*
* @param grantedTo - A list of entities that will get access to the file.
* @param _public - Specifies whether all users have access to the file or not.
*/
createPermission(actions, grantedTo, _public) {
return this.post("/permissions", {
actions: Array.isArray(actions) ? actions : [actions],
grantedTo,
public: _public,
})
.then((response) => response.json())
.then((data) => new Permission(data, this.id, this.httpClient));
}
/**
* Removes the specified permission from the file.
*
* @param permissionId - Permission ID.
* @returns Returns the raw data of a deleted permission. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Permission | Open Cloud File Permissions API}.
*/
deletePermission(permissionId) {
return super.delete(`/permissions/${permissionId}`).then((response) => response.json());
}
/**
* Uploads the new version of the file to the server, convert the geometry data and extract properties
* as needed.
*
* @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. The geometry data type is the
* same as the original file.
* @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 uploadVersion(file, params = {
waitForDone: false,
}) {
const result = await this.httpClient
.uploadFile(this.getEndpointPath("/versions"), file, (progress) => { var _a; return (_a = params.onProgress) === null || _a === undefined ? undefined : _a.call(params, progress, file); }, {
headers: this.headers,
})
.then((xhr) => JSON.parse(xhr.responseText))
.then((data) => new File(data, this.httpClient));
let geometryType = "";
if (this.versions[0].status.geometryGltf.state !== "none")
geometryType = "gltf";
if (this.versions[0].status.geometry.state !== "none")
geometryType = "vsfx";
params = { ...params };
if (params.geometry === undefined)
params.geometry = geometryType !== "";
if (params.properties === undefined)
params.properties = this.versions[0].status.properties.state !== "none";
const jobs = [];
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();
await this.checkout();
return result;
}
/**
* Returns a list of version files.
*/
getVersions() {
return this.get("/versions")
.then((response) => response.json())
.then((files) => files.map((data) => new File(data, this.httpClient)))
.then((files) => files.map((file) => (file.id == file.originalFileId ? file.useVersion(0) : file)));
}
/**
* Returns information about the specified version file.
*
* @param version - Desired version.
*/
getVersion(version) {
return this.get(`/versions/${version}`)
.then((response) => response.json())
.then((data) => new File(data, this.httpClient))
.then((file) => (file.id == file.originalFileId ? file.useVersion(0) : file));
}
/**
* Deletes the specified version file.
*
* @param version - Version to delete.
* @returns Returns the raw data of a deleted version file. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Files | Open Cloud Files API}.
*/
async deleteVersion(version) {
const response = await super.delete(`/versions/${version}`);
const data = await response.json();
await this.checkout();
return data;
}
/**
* Replaces the active version of the file with the selected version.
*
* @param version - Desired active version.
*/
setActiveVersion(version) {
return this.update({ activeVersion: version });
}
/**
* Makes the given version active on client side. Does not change the active file version on the
* server.
*
* This version change will affect the result:
*
* - {@link getModels | getModels()}
* - {@link getProperties | getProperties()}
* - {@link searchProperties | searchProperties()}
* - {@link getCdaTree | getCdaTree()}
* - {@link download | download()}
* - {@link downloadResource | downloadResource()}
* - {@link createJob | createJob()}
* - {@link extractGeometry | extractGeometry()}
* - {@link extractProperties | extractProperties()}
* - {@link validate | validate()}
* - {@link waitForDone | waitForDone()}
* - Viewer.open()
*
* Other clients will still continue to use the current active version of the file. Use `undefined` to
* revert back to the active version.
*
* You need to reload the file data using {@link checkout | checkout()} to match the size and status
* fields to the version you selected.
*/
useVersion(version) {
return super.useVersion(version);
}
/**
* Deletes the source file of the active file version from the server.
*/
async deleteSource() {
const response = await super.delete("/source");
this.data = await response.json();
return this;
}
/**
* Creates a file shared link.
*
* @param permissions - Share permissions.
*/
async createSharedLink(permissions) {
const shares = new Endpoint("/shares", this.httpClient, this.headers);
const response = await shares.post("", { fileId: this.id, permissions });
const data = await response.json();
await this.checkout();
return new SharedLink(data, this.httpClient);
}
/**
* Returns information about the file shared link or `undefined` if file is not shared.
*/
async getSharedLink() {
if (!this.sharedLinkToken)
return Promise.resolve(undefined);
const shares = new Endpoint("/shares", this.httpClient, this.headers);
const response = await shares.get(`/${this.sharedLinkToken}`);
const data = await response.json();
return new SharedLink(data, this.httpClient);
}
/**
* Deletes the file shared link.
*
* @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}.
*/
async deleteSharedLink() {
const shares = new Endpoint("/shares", this.httpClient, this.headers);
const response = await shares.delete(`/${this.sharedLinkToken}`);
const data = await response.json();
await this.checkout();
return data;
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* A role determines what actions allowed to be performed by {@link User | users} on a
* {@link Project | project}.
*/
class Role extends Endpoint {
/**
* @param data - Raw role data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
* @param projectId - Owner project ID.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, projectId, httpClient) {
super("", httpClient);
this.projectId = projectId;
this.data = data;
}
/**
* Role description.
*/
get description() {
return this.data.description;
}
set description(value) {
this._data.description = value;
}
/**
* Raw role data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
this.path = `/projects/${this.projectId}/roles/${value.name}`;
}
/**
* Role name.
*/
get name() {
return this.data.name;
}
set name(value) {
this._data.name = value;
}
/**
* Role actions are allowed to be performed.
*/
get permissions() {
return this.data.permissions;
}
set permissions(value) {
this.data.permissions = value || {};
}
/**
* Reloads role data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates role data on the server.
*
* @param data - Raw role data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes a role from the project.
*
* @returns Returns the raw data of a deleted role. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves role properties changes to the server. Call this method to update role data on the server
* after any property changes.
*/
save() {
return this.update(this.data);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a {@link User | user} who has access to
* the {@link Project | project}.
*/
class Member extends Endpoint {
/**
* @param data - Raw member data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
* @param projectId - Owner project ID.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, projectId, httpClient) {
super(`/projects/${projectId}/members/${data.id}`, httpClient);
this.data = data;
}
/**
* Raw member data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
this._data.user.avatarUrl = `${this.httpClient.serverUrl}/users/${this._data.user.userId}/avatar`;
this._data.user.fullName = userFullName(this._data.user);
this._data.user.initials = userInitials(this._data.user.fullName);
}
/**
* Unique member ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* Member role name in the project. See {@link Project.getRoles | Project.getRoles()} for list of
* project roles.
*/
get role() {
return this.data.role;
}
set role(value) {
this.data.role = value;
}
/**
* Member type. Can be `owner` or `user`.
*
* @readonly
*/
get type() {
return this.data.type;
}
/**
* User information.
*
* @readonly
*/
get user() {
return this.data.user;
}
/**
* Reloads member data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates member data on the server.
*
* @param data - Raw member data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Removes a member from the project.
*
* @returns Returns the raw data of a deleted member. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves member properties changes to the server. Call this method to update member data on the server
* after any property changes.
*/
save() {
return this.update(this.data);
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a project on the Open Cloud Server and
* managing its {@link Role | roles}, {@link Member | members} and models.
*/
class Project extends Endpoint {
/**
* @param data - Raw project data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, httpClient) {
super(`/projects/${data.id}`, httpClient);
this.data = data;
}
/**
* Project features the user has access to.
*
* @readonly
*/
get authorization() {
return this.data.authorization;
}
/**
* Project creation time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get createdAt() {
return this.data.createdAt;
}
/**
* Project custom fields object, to store custom data.
*/
get customFields() {
return this.data.customFields;
}
set customFields(value) {
this.data.customFields = value;
}
/**
* Raw project data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
this._data.previewUrl = value.avatarUrl
? `${this.httpClient.serverUrl}/projects/${this._data.id}/preview?updated=${value.updatedAt}`
: "";
this._data.owner.avatarUrl = `${this.httpClient.serverUrl}/users/${this._data.owner.userId}/avatar`;
this._data.owner.fullName = userFullName(this._data.owner);
this._data.owner.initials = userInitials(this._data.owner.fullName);
}
/**
* Project description.
*/
get description() {
return this.data.description;
}
set description(value) {
this.data.description = value;
}
/**
* Project end date in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*/
get endDate() {
return this.data.endDate;
}
set endDate(value) {
this.data.endDate = value instanceof Date ? value.toISOString() : value;
}
/**
* Unique project ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* The number of members in the project.
*
* @readonly
*/
get memberCount() {
return this.data.memberCount;
}
/**
* The number of models in the project.
*
* @readonly
*/
get modelCount() {
return this.data.modelCount;
}
/**
* Project name.
*/
get name() {
return this.data.name;
}
set name(value) {
this.data.name = value;
}
/**
* Project owner information.
*
* @readonly
*/
get owner() {
return this.data.owner;
}
/**
* Project preview image URL or empty string if the project does not have a preview. Use
* {@link Project.setPreview | setPreview()} to change preview image.
*
* @readonly
*/
get previewUrl() {
return this._data.previewUrl;
}
/**
* `true` if project is shared project.
*/
get public() {
return this.data.public;
}
set public(value) {
this.data.public = value;
}
/**
* Project start date in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*/
get startDate() {
return this.data.startDate;
}
set startDate(value) {
this.data.startDate = value instanceof Date ? value.toISOString() : value;
}
/**
* The number of topics in the project.
*
* @readonly
*/
get topicCount() {
return this.data.topicCount;
}
/**
* Project last update time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get updatedAt() {
return this.data.updatedAt;
}
/**
* Reloads project data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates project data on the server.
*
* @param data - Raw project data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes a project from the server.
*
* @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}.
*/
delete() {
return super
.delete("")
.then((response) => response.text())
.then((text) => {
// TODO fix for server 23.5 and below
try {
return JSON.parse(text);
}
catch {
return { id: this.id };
}
});
}
/**
* Saves project properties changes to the server. Call this method to update project data on the
* server after any property changes.
*/
save() {
return this.update(this.data);
}
/**
* Sets or removes the project preview.
*
* @param image - Preview image. Can be a
* {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL} string,
* {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer},
* {@link https://developer.mozilla.org/docs/Web/API/Blob/Blob | Blob} or
* {@link https://developer.mozilla.org/docs/Web/API/File | Web API File} object. Setting the `image`
* to `null` will remove the preview.
*/
async setPreview(image) {
if (!image) {
await this.deletePreview();
}
else {
const response = await this.post("/preview", image);
this.data = await response.json();
}
return this;
}
/**
* Removes the project preview.
*/
async deletePreview() {
const response = await super.delete("/preview");
this.data = await response.json();
return this;
}
/**
* Returns a list of project roles. Project members have different abilities depending on the role they
* have in a project.
*/
getRoles() {
return this.get("/roles")
.then((response) => response.json())
.then((array) => array.map((data) => new Role(data, this.id, this.httpClient)));
}
/**
* Returns information about the specified project role.
*
* @param name - Role name.
*/
getRole(name) {
return this.get(`/roles/${name}`)
.then((response) => response.json())
.then((data) => new Role(data, this.id, this.httpClient));
}
/**
* Creates a new project role.
*
* @param name - Role name.
* @param description - Role description.
* @param permissions - Actions are allowed to be performed for the role.
*/
createRole(name, description, permissions) {
return this.post("/roles", {
name,
description,
permissions: permissions || {},
})
.then((response) => response.json())
.then((data) => new Role(data, this.id, this.httpClient));
}
/**
* Deletes the specified project role.
*
* @param name - Role name.
* @returns Returns the raw data of a deleted role. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
deleteRole(name) {
return super.delete(`/roles/${name}`).then((response) => response.json());
}
/**
* Returns a list of project members.
*/
getMembers() {
return this.get("/members")
.then((response) => response.json())
.then((array) => array.map((data) => new Member(data, this.id, this.httpClient)));
}
/**
* Returns information about the specified project member.
*
* @param memberId - Member ID.
*/
getMember(memberId) {
return this.get(`/members/${memberId}`)
.then((response) => response.json())
.then((data) => new Member(data, this.id, this.httpClient));
}
/**
* Adds a user to the project to become a member and have permission to perform actions.
*
* @param userId - User ID.
* @param role - Role name from the list of project {@link getRoles | roles}.
*/
addMember(userId, role) {
return this.post("/members", { userId, role })
.then((response) => response.json())
.then((data) => new Member(data, this.id, this.httpClient));
}
/**
* Removes the specified member from a project.
*
* @param memberId - Member ID.
* @returns Returns the raw data of a deleted member. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Project | Open Cloud Projects API}.
*/
removeMember(memberId) {
return super.delete(`/members/${memberId}`).then((response) => response.json());
}
/**
* Information about the file (model) that can be reference in the project topics.
*
* @typedef {any} FileInformation
* @property {any[]} display_information - The list of fields to allow users to associate the file with
* a server model.
* @property {string} display_information.field_display_name - Field display name.
* @property {string} display_information.field_value - Field value.
* @property {any} file - The file reference object.
* @property {string} file.file_name - File name.
* @property {string} file.reference - File ID.
*/
/**
* Returns a list of project files. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/bcf3.html#ProjectFilesInformation | Open Cloud BCF3 API}.
*
* This list contains all files that the project has access to. To add a file to this list, create a
* {@link IGrantedTo.project | project} permission on the file using
* {@link File.createPermission | File.createPermission()}.
*/
getFilesInformation() {
const bcfProjects = new Endpoint("/bcf/3.0/projects", this.httpClient, this.headers);
return bcfProjects
.get(`/${this.id}/files_information`)
.then((response) => response.json())
.then((items) => {
items.forEach((item) => {
const getFieldValue = (displayName) => {
return (item.display_information.find((x) => x.field_display_name === displayName) || {}).field_value;
};
const previewUrl = `${this.httpClient.serverUrl}/files/${item.file.reference}/preview`;
const ownerAvatarUrl = `${this.httpClient.serverUrl}/users/${getFieldValue("Owner")}/avatar`;
const ownerFirstName = getFieldValue("Owner First Name");
const ownerLastName = getFieldValue("Owner Last Name");
const ownerUserName = getFieldValue("Owner User Name");
const ownerFullName = userFullName(ownerFirstName, ownerLastName, ownerUserName);
const ownerInitials = userInitials(ownerFullName);
item.display_information.push({ field_display_name: "Preview URL", field_value: previewUrl });
item.display_information.push({ field_display_name: "Owner Avatar URL", field_value: ownerAvatarUrl });
item.display_information.push({ field_display_name: "Owner Full Name", field_value: ownerFullName });
item.display_information.push({ field_display_name: "Owner Initials", field_value: ownerInitials });
// updatedBy since 24.10
const updatedByAvatarUrl = `${this.httpClient.serverUrl}/users/${getFieldValue("Updated By")}/avatar`;
const updatedByFirstName = getFieldValue("Updated By First Name");
const updatedByLastName = getFieldValue("Updated By Last Name");
const updatedByUserName = getFieldValue("Updated By User Name");
const updatedByFullName = userFullName(updatedByFirstName, updatedByLastName, updatedByUserName);
const updatedByInitials = userInitials(updatedByFullName);
item.display_information.push({
field_display_name: "Updated By Avatar URL",
field_value: updatedByAvatarUrl,
});
item.display_information.push({ field_display_name: "Updated By Full Name", field_value: updatedByFullName });
item.display_information.push({ field_display_name: "Updated By Initials", field_value: updatedByInitials });
// geometryType since 24.12
const geometry = getFieldValue("Geometry Status");
const geometryGltf = getFieldValue("GeometryGltf Status");
const geometryType = geometry === "done" ? "vsfx" : geometryGltf === "done" ? "gltf" : "";
item.display_information.push({ field_display_name: "Geometry Type", field_value: geometryType });
});
return items;
});
}
/**
* Returns a list of project files.
*/
getModels() {
return this.getFilesInformation()
.then((filesInformation) => filesInformation.map((item) => item.file.reference))
.then((ids) => {
const files = new Endpoint("/files", this.httpClient, this.headers);
return files.get(`?id=${ids.join("|")}`);
})
.then((response) => response.json())
.then((files) => files.result.map((data) => new File(data, this.httpClient)));
}
/**
* Adds a file to the project with specified permissions.
*
* To change file permissions for the project use {@link Permission.actions}.
*
* @param fileId - File ID.
* @param actions - Actions are allowed to be performed on a file:
*
* - `read` - The ability to read file description, geometry data and properties.
* - `readSourceFile` - The ability to download source file.
* - `write` - The ability to modify file name, description and references.
* - `readViewpoint` - The ability to read file viewpoints.
* - `createViewpoint` - The ability to create file viewpoints.
*
* @param _public - Specifies whether all users have access to the file or not.
* @returns Returns a file instance added to the project.
*/
async addModel(fileId, actions, _public) {
const files = new Endpoint("/files", this.httpClient, this.headers);
const file = await files
.get(`/${fileId}`)
.then((response) => response.json())
.then((data) => new File(data, this.httpClient));
const grantedTo = [{ project: { id: this.id, name: this.name } }];
await file.createPermission(actions, grantedTo, _public);
return file;
}
/**
* Removes the specified file from a project.
*
* @param fileId - File ID.
* @returns Returns a file instance removed from the project.
*/
async removeModel(fileId) {
const files = new Endpoint("/files", this.httpClient, this.headers);
const file = await files
.get(`/${fileId}`)
.then((response) => response.json())
.then((data) => new File(data, this.httpClient));
const permissions = await file.getPermissions();
await Promise.allSettled(permissions
.filter((permission) => permission.grantedTo.some((x) => { var _a; return ((_a = x.project) === null || _a === undefined ? undefined : _a.id) === this.id; }))
.map((permission) => permission.delete()));
return file;
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a Open Cloud Server user and manage
* its data.
*/
class User extends Endpoint {
/**
* @param data - Raw user data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Users | Open Cloud Users API}.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, httpClient) {
super("", httpClient);
this.data = data;
}
/**
* User avatar image URL or empty string if the user does not have an avatar. Use
* {@link setAvatar | setAvatar()} to change avatar image.
*
* @readonly
*/
get avatarUrl() {
return this._data.avatarUrl;
}
/**
* `true` if user is allowed to create a projects.
*
* Only administrators can change create project permission.
*/
get canCreateProject() {
return this.data.canCreateProject;
}
set canCreateProject(value) {
this._data.canCreateProject = value;
}
/**
* Account registration time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*
* @readonly
*/
get createAt() {
return this.data.createAt;
}
/**
* User custom fields object, to store custom data.
*/
get customFields() {
return this.data.customFields;
}
set customFields(value) {
this._data.customFields = value;
}
/**
* Raw user data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Users | Open Cloud Users API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
this._data.avatarUrl = value.avatarImage
? `${this.httpClient.serverUrl}/users/${this._data.id}/avatar?updated=${value.lastModified}`
: "";
this._data.fullName = userFullName(this._data);
this._data.initials = userInitials(this._data.fullName);
}
/**
* User email.
*/
get email() {
return this.data.email;
}
set email(value) {
this._data.email = value;
}
/**
* The user's email confirmation code, or an empty string if the email has already been confirmed.
*
* To send the confirmation code to the server, use
* {@link Client.confirmUserEmail | Client.confirmUserEmail()}.
*
* @readonly
*/
get emailConfirmationId() {
return this.data.emailConfirmationId;
}
/**
* First name.
*/
get firstName() {
return this.data.firstName;
}
set firstName(value) {
this._data.firstName = value;
}
/**
* Full name. Returns the user's first and last name. If first name and last names are empty, returns
* the user name.
*
* @readonly
*/
get fullName() {
return this.data.fullName;
}
/**
* Unique user ID.
*
* @readonly
*/
get id() {
return this.data.id;
}
/**
* User initials. Returns a first letters of the user's first and last names. If first name and last
* names are empty, returns the first letter of the user name.
*
* @readonly
*/
get initials() {
return this.data.initials;
}
/**
* `true` if user is an administrator.
*
* Only administrators can change user type.
*/
get isAdmin() {
return this.data.isAdmin;
}
set isAdmin(value) {
this._data.isAdmin = value;
}
/**
* `false` if the user has not yet confirmed his email address.
*
* @readonly
*/
get isEmailConfirmed() {
return this.data.isEmailConfirmed;
}
/**
* User last update time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*/
get lastModified() {
return this.data.lastModified;
}
/**
* Last name.
*/
get lastName() {
return this.data.lastName;
}
set lastName(value) {
this._data.lastName = value;
}
/**
* User last sign in time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*/
get lastSignIn() {
return this.data.lastSignIn;
}
/**
* The maximum number of projects that a user can create.
*
* Only administrators can change projects limit.
*/
get projectsLimit() {
return this.data.projectsLimit;
}
set projectsLimit(value) {
this._data.projectsLimit = value;
}
/**
* The identity provider used to create the account. Can be `ldap`, `oauth`, `saml` or empty for local
* accounts.
*
* @readonly
*/
get providerType() {
return this.data.providerType;
}
/**
* User storage size on the server for uploading files.
*
* Only administrators can change storage size.
*/
get storageLimit() {
return this.data.storageLimit;
}
set storageLimit(value) {
this._data.storageLimit = value;
}
/**
* The total size of the user's files in the storage.
*
* @readonly
*/
get storageUsed() {
return this.data.storageUsed;
}
/**
* The user's access token (API key). Use {@link Client.signInWithToken | Client.signInWithToken()} to
* sign in to the server using this token.
*
* @readonly
*/
get token() {
return this.data.tokenInfo.token;
}
/**
* User name.
*/
get userName() {
return this.data.userName;
}
set userName(value) {
this._data.userName = value;
}
/**
* Reloads user data from the server.
*
* Only administrators can checkout other users. If the current logged in user is not an administrator,
* they can only checkout themselves, otherwise an exception will be thrown.
*/
async checkout() {
if (this.httpClient.signInUserIsAdmin) {
const response = await this.get(`/users/${this.id}`);
const data = await response.json();
this.data = { id: data.id, ...data.userBrief };
}
else if (this.id === this.httpClient.signInUserId) {
const response = await this.get("/user");
const data = await response.json();
this.data = { id: this.id, ...data };
}
else {
return Promise.reject(new FetchError(403));
}
return this;
}
/**
* Updates user data on the server.
*
* Only administrators can update other users. If the current logged in user is not an administrator,
* they can only update themself, otherwise an exception will be thrown.
*
* @param data - Raw user data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#Users | Open Cloud Users API}.
*/
async update(data) {
if (this.httpClient.signInUserIsAdmin) {
const response = await this.put(`/users/${this.id}`, { isAdmin: data.isAdmin, userBrief: data });
const newData = await response.json();
this.data = { id: newData.id, ...newData.userBrief };
}
else if (this.id === this.httpClient.signInUserId) {
const response = await this.put("/user", data);
const newData = await response.json();
this.data = { id: this.id, ...newData };
}
else {
return Promise.reject(new FetchError(403));
}
return this;
}
/**
* Deletes a 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.
*
* @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}.
*/
delete() {
if (this.httpClient.signInUserIsAdmin) {
return super
.delete(`/users/${this.id}`)
.then((response) => response.json())
.then((data) => {
if (this.id === this.httpClient.signInUserId) {
delete this.httpClient.headers["Authorization"];
this.httpClient.signInUserId = "";
this.httpClient.signInUserIsAdmin = false;
}
return data;
});
}
else {
return Promise.reject(new FetchError(403));
}
}
/**
* Saves user properties changes to the server. Call this method to update user data on the server
* after any property changes.
*/
save() {
return this.update(this.data);
}
/**
* Sets or removes the user avatar.
*
* Only administrators can set the avatar of other users. If the current logged in user is not an
* administrator, they can only set their avatar, otherwise an exception will be thrown.
*
* @param image - Avatar image. Can be a
* {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL} string,
* {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer},
* {@link https://developer.mozilla.org/docs/Web/API/Blob/Blob | Blob} or
* {@link https://developer.mozilla.org/docs/Web/API/File | Web API File} object. Setting the `image`
* to `null` will remove the avatar.
*/
async setAvatar(image) {
if (!image) {
await this.deleteAvatar();
}
else if (this.httpClient.signInUserIsAdmin) {
const response = await this.post(`/users/${this.id}/avatar`, image);
const data = await response.json();
this.data = { id: data.id, ...data.userBrief };
}
else if (this.id === this.httpClient.signInUserId) {
const response = await this.post("/user/avatar", image);
const data = await response.json();
this.data = { id: this.id, ...data };
}
else {
return Promise.reject(new FetchError(403));
}
return this;
}
/**
* Removes the user avatar.
*
* Only administrators can remove the avatar of other users. If the current logged in user is not an
* administrator, they can only remove their avatar, otherwise an exception will be thrown.
*/
async deleteAvatar() {
if (this.httpClient.signInUserIsAdmin) {
const response = await super.delete(`/users/${this.id}/avatar`);
const data = await response.json();
this.data = { id: data.id, ...data.userBrief };
}
else if (this.id === this.httpClient.signInUserId) {
const response = await super.delete("/user/avatar");
const data = await response.json();
this.data = { id: this.id, ...data };
}
else {
return Promise.reject(new FetchError(403));
}
return this;
}
/**
* Changes the user password.
*
* Only administrators can change the passwords of other users. If the current logged in user is not an
* administrator, they can only change their password, otherwise an exception will be thrown.
*
* To change their password, non-administrator users must specify their old password.
*
* @param newPassword - New user password.
* @param oldPassword - Old user password. Only required for non-administrator users to change their
* password.
*/
async changePassword(newPassword, oldPassword) {
if (this.httpClient.signInUserIsAdmin) {
const response = await this.put(`/users/${this.id}/password`, { new: newPassword });
const data = await response.json();
this.data = { id: data.id, ...data.userBrief };
}
else if (this.id === this.httpClient.signInUserId) {
const response = await this.put("/user/password", { old: oldPassword, new: newPassword });
const data = await response.json();
this.data = { id: this.id, ...data };
}
else {
return Promise.reject(new FetchError(403));
}
return this;
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides properties and methods for obtaining information about a OAuth 2.0 client that have access
* the Open Cloud Server API.
*/
class OAuthClient extends Endpoint {
/**
* @param data - Raw client data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#OAuthClient | Open Cloud OAuth Clients API}.
* @param httpClient - HTTP client instance used to send requests to the REST API server.
*/
constructor(data, httpClient) {
super(`/oauth/clients/${data.clientId}`, httpClient);
this.data = data;
}
/**
* OAuth 2.0 server authorization endpoint.
*/
get authUrl() {
return this.data.authUrl;
}
/**
* OAuth 2.0 server token endpoint.
*/
get accessTokenUrl() {
return this.data.accessTokenUrl;
}
/**
* Unique client ID.
*
* @readonly
*/
get clientId() {
return this.data.clientId;
}
/**
* Client creation time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*/
get createdAt() {
return this.data.createdAt;
}
/**
* Client application description.
*/
get description() {
return this.data.description;
}
set description(value) {
this._data.description = value;
}
/**
* Client data received from the server. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#OAuthClient | Open Cloud OAuth Clients API}.
*
* @readonly
*/
get data() {
return this._data;
}
set data(value) {
this._data = value;
}
/**
* Client application name.
*/
get name() {
return this.data.name;
}
set name(value) {
this._data.name = value;
}
/**
* The endpoint to which the OAuth 2.0 server sends the response.
*/
get redirectUrl() {
return this.data.redirectUrl;
}
set redirectUrl(value) {
this.data.redirectUrl = value;
}
/**
* Client secret.
*
* @readonly
*/
get secret() {
return this.data.secret;
}
/**
* Client last update time (UTC) in the format specified in
* {@link https://www.wikipedia.org/wiki/ISO_8601 | ISO 8601}.
*/
get updatedAt() {
return this.data.updatedAt;
}
/**
* Reloads clien data from the server.
*/
async checkout() {
const response = await this.get("");
this.data = await response.json();
return this;
}
/**
* Updates client data on the server.
*
* Only administrators can update OAuth clients. If the current logged in user is not an administrator,
* an exception will be thrown.
*
* @param data - Raw client data. For more information, see
* {@link https://cloud.opendesign.com/docs//pages/server/api.html#OAuthClient | Open Cloud OAuth Clients API}.
*/
async update(data) {
const response = await this.put("", data);
this.data = await response.json();
return this;
}
/**
* Deletes a 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.
*
* @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}.
*/
delete() {
return super.delete("").then((response) => response.json());
}
/**
* Saves client properties changes to the server. Call this method to update client data on the server
* after any property changes.
*
* Only administrators can update OAuth clients. If the current logged in user is not an administrator,
* an exception will be thrown.
*/
save() {
return this.update(this.data);
}
/**
* Revokes the access tokens for all users of the client application.
*/
async revoke() {
await this.post("/revoke");
return this;
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
class SharedFile extends File {
constructor(data, password, httpClient) {
super(data.file, httpClient);
this.path = `/shares/${data.file.sharedLinkToken}`;
this.headers = { "InWeb-Password": password };
}
async checkout() {
const response = await this.get("/info");
const data = await response.json();
this.data = data.file;
return this;
}
async update(data) {
const response = await this.put("/info", data);
this.data = await response.json();
return this;
}
getVersions() {
return Promise.resolve(undefined);
}
useVersion(version) {
return this;
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
/**
* Provides methods for managing Open Cloud Server resources such as users, files, assemblies, jobs,
* projects, etc.
*/
class Client extends EventEmitter2 {
/**
* @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 = {}) {
super();
this._serverUrl = "";
this._httpClient = new HttpClient("");
this._user = null;
this.eventEmitter = this;
this.configure(params);
}
/**
* Open Cloud REST API server URL. Use {@link configure | configure()} to change server URL.
*
* @readonly
*/
get serverUrl() {
return this._serverUrl;
}
/**
* HTTP client instance used to send requests to the REST API server.
*
* @readonly
*/
get httpClient() {
return this._httpClient;
}
/**
* Deprecated since `25.3`. Use `Viewer.options()` instead to change `Viewer` parameters.
*
* @deprecated
*/
get options() {
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) {
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() {
return this.httpClient
.get("/version")
.then((response) => response.json())
.then((data) => ({
...data,
server: data.version,
client: "26.9.1",
}));
}
/**
* 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, password, userName) {
return this.httpClient
.post("/register", {
email,
password,
userName: userName !== null && userName !== undefined ? 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, password) {
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) {
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, password) {
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) {
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() {
this.clearCurrentUser();
}
// Save the current logged in user information for internal use.
setCurrentUser(data) {
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;
}
clearCurrentUser() {
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() {
if (this._user && !this.httpClient.signInUserId)
this._user = null;
return this._user;
}
/**
* Returns the list of server enabled indentity providers.
*/
getIdentityProviders() {
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() {
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) {
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, limit) {
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) {
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, redirectUrl, description) {
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) {
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() {
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) {
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, password, params = {}) {
const { isAdmin, userName, ...rest } = params;
return this.httpClient
.post("/users", {
isAdmin,
userBrief: {
...rest,
email,
userName: userName !== null && userName !== undefined ? 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) {
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, limit, name, ext, ids, sortByDesc, sortField, shared) {
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) {
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 - Run File Converter job to convert geometry data after uploading the file.
* Can be:
*
* - `true` - Convert file geometry data to `VSFX` format for opening in `VisualizeJS` 3D viewer.
* - `vsfx` - Convert file geometry data to `VSFX` format for opening in `VisualizeJS` 3D viewer.
* - `gltf` - Convert file geometry data to `glTF` format for opening in `Three.js` 3D viewer.
*
* @param params.properties - Run File Converter job to extract properties after uploading the file.
* @param params.jobParameters - Parameters for the File Converter jobs. Use this to specify aditional
* parameters for retrieving the geometry and properties of uploaded file. Can be given as command
* line arguments in form `--arg=value`.
* @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, params = {
geometry: true,
properties: false,
waitForDone: false,
}) {
const result = await this.httpClient
.uploadFile("/files", file, (progress) => {
var _a;
this.emitEvent({ type: "uploadprogress", data: progress, file });
(_a = params.onProgress) === null || _a === undefined ? undefined : _a.call(params, progress, file);
})
.then((xhr) => JSON.parse(xhr.responseText))
.then((data) => new File(data, this.httpClient));
const geometryType = typeof params.geometry === "string" ? params.geometry : "vsfx";
const jobParameters = params.jobParameters || {};
const jobs = [];
if (params.geometry)
jobs.push((await result.extractGeometry(geometryType, jobParameters.geometry)).outputFormat);
if (params.properties)
jobs.push((await result.extractProperties(jobParameters.properties)).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) {
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, onProgress, signal) {
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, limit, start, sortByDesc, sortField) {
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) {
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:
*
* - `geometry` - Convert file geometry data to `VSFX` format for opening in `VisualizeJS` 3D viewer.
* - `geometryGltf` - Convert file geometry data to `glTF` format for opening in `Three.js` 3D viewer.
* - `properties` - Extract file properties.
* - `validation` - Validate the IFC file.
* - `dwg`, `obj`, `gltf`, `glb`, `vsf`, `pdf`, `3dpdf` - Export file to the specified format.
* - Other custom job name. Custom job must be registered in the job templates before running.
*
* @param parameters - Parameters for the File Converter jobs or custom job. Can be given as command
* line arguments in form `--arg=value`.
*/
createJob(fileId, outputFormat, parameters) {
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) {
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, limit, name, ids, sortByDesc, sortField) {
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) {
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.jobParameters - Parameters for the File Converter jobs. Use this to specify aditional
* parameters for generating the geometry and properties of the new assembly. Can be given as command
* line arguments in form `--arg=value`.
* @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, name, params = {}) {
const jobParameters = params.jobParameters || {};
return this.httpClient
.post("/assemblies", {
name,
files,
jobParameters: {
geometry: parseArgs(jobParameters.geometry),
properties: parseArgs(jobParameters.properties),
},
})
.then((response) => response.json())
.then((data) => new Assembly(data, this.httpClient))
.then((result) => (params.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) {
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, limit, name, ids, sortByDesc) {
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) {
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, description, startDate, endDate) {
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) {
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) {
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, permissions) {
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) {
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, password) {
return this.httpClient
.get(`/shares/${token}/info`, { headers: { "InWeb-Password": password } })
.then((response) => response.json())
.then((data) => new SharedFile(data, password, this.httpClient));
}
}
///////////////////////////////////////////////////////////////////////////////
// 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.
///////////////////////////////////////////////////////////////////////////////
const version = "26.9.1";
exports.Assembly = Assembly;
exports.ClashTest = ClashTest;
exports.Client = Client;
exports.Endpoint = Endpoint;
exports.FetchError = FetchError;
exports.File = File;
exports.Job = Job;
exports.Member = Member;
exports.Model = Model;
exports.OAuthClient = OAuthClient;
exports.Permission = Permission;
exports.Project = Project;
exports.Role = Role;
exports.SharedFile = SharedFile;
exports.SharedLink = SharedLink;
exports.User = User;
exports.parseArgs = parseArgs;
exports.statusText = statusText;
exports.userFullName = userFullName;
exports.userInitials = userInitials;
exports.version = version;
exports.waitFor = waitFor;
}));
//# sourceMappingURL=client.js.map