@inweb/client
Version:
JavaScript REST API client for the Open Cloud Server
1,233 lines (1,227 loc) • 231 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;
}
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 range of resource file contents to download.
* @param requestId - Request ID for download progress callback.
* @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` 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 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.
*/
getProperties(handles) {
const relativePath = handles !== undefined ? `/properties?handles=${handles}` : "/properties";
return this.get(relativePath).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 range of resource file contents to download.
* @param requestId - Request ID for download progress callback.
* @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, 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 | AbortControlle