dalux-build-api
v2.0.0
Published
Node.js client for the Dalux Build API
Maintainers
Readme
Dalux Build API
API clients for the Dalux Build REST API, available in two languages:
| Language | Location | Documentation |
| -------- | -------------------- | ------------------------------------ |
| Node.js | / | See below |
| Python | /python | python/README.md |
Node.js Client
A lightweight Node.js client for the Dalux Build REST API.
Requirements
- Node.js 14 or later
Installation
npm install dalux-build-apiGetting Started
To access the API you need:
- A company-specific base URL (obtain from Dalux support at [email protected]).
- An API key — managed via Settings › Integrations › API Identities inside the Dalux Build UI.
const { createClient } = require("dalux-build-api");
const dalux = createClient({
baseUrl: "https://<your-company>.dalux.com/api",
apiKey: "YOUR_API_KEY",
});The returned object exposes one namespace per API group (see API Reference below).
Examples
List all projects
const projects = await dalux.projects.listProjects();
console.log(projects);Get a specific project
const project = await dalux.projects.getProject("my-project-id");
console.log(project);List tasks on a project
const tasks = await dalux.tasks.getProjectTasks("my-project-id", {
updatedAfter: "2024-01-01",
});
console.log(tasks);Tasks: OData typeId shorthand and fetch all pages
getProjectTasks forwards OData query options (for example $filter). You can also pass typeId; it is expanded to $filter=data/type/typeId eq '<typeId>' unless you already set $filter.
const byType = await dalux.tasks.getProjectTasks("my-project-id", {
typeId: "some-type-guid",
});
// All pages merged (bookmark pagination; matches Python client behaviour)
const allTasks = await dalux.tasks.getAllProjectTasks(
"my-project-id",
{ typeId: "some-type-guid" },
false,
);Files: browse (6.1), fetch all pages, download
listFiles and getAllFiles call GET /6.1/projects/{projectId}/file_areas/{fileAreaId}/files (Dalux listFiles). Supported query parameters include folderId, updatedAfter, and includeProperties (see the official spec). Single-file metadata still uses GET /5.0/.../files/{fileId} (getFile).
const allFiles = await dalux.files.getAllFiles(
"my-project-id",
"my-file-area-id",
{ folderId: "folder-guid" },
);
const file = await dalux.files.getFile(
"my-project-id",
"my-file-area-id",
"file-guid",
{
download: true,
savePath: "./downloads",
},
);
const saved = await dalux.files.downloadFileFromLink(
downloadUrl,
"model.ifc",
"./downloads",
);
await dalux.files.bulkDownloadFolder(
"my-project-id",
"my-file-area-id",
"folder-guid",
"./out",
{
filenameExtensions: [".ifc"],
verbose: true,
},
);Upload a file (chunked)
const fs = require("fs");
// 1. Create an upload slot
const { uploadGuid } = await dalux.fileUpload.createUpload(
"my-project-id",
"my-file-area-id",
{ fileName: "drawing.pdf", mimeType: "application/pdf" },
);
// 2. Upload the file in one chunk
const content = fs.readFileSync("./drawing.pdf");
await dalux.fileUpload.uploadFilePart(
"my-project-id",
"my-file-area-id",
uploadGuid,
content,
);
// 3. Finalize the upload
const result = await dalux.fileUpload.finishUpload(
"my-project-id",
"my-file-area-id",
uploadGuid,
{ folderId: "target-folder-id" },
);
console.log("New file ID:", result.fileId);Authentication
Every request automatically includes the X-API-KEY header with the API key supplied to createClient. No additional configuration is required.
Error Handling
All methods return Promises. Network or HTTP errors (4xx / 5xx) are thrown as Axios errors, so wrap calls with try/catch or .catch():
try {
const project = await dalux.projects.getProject("unknown-id");
} catch (err) {
console.error(err.response?.status, err.response?.data);
}API Reference
All API namespaces are accessible on the object returned by createClient:
| Namespace | Class | Description |
| ------------------ | --------------------- | -------------------------------------------------------------- |
| projects | ProjectsApi | List, get, create and update projects; manage project metadata |
| companies | CompaniesApi | Project companies (CRUD) |
| companyCatalog | CompanyCatalogApi | Company catalog (CRUD + metadata) |
| tasks | TasksApi | Tasks, approvals, safety issues, observations & good practices |
| fileAreas | FileAreasApi | File areas on a project |
| files | FilesApi | Files within a file area |
| folders | FoldersApi | Folders within a file area |
| fileUpload | FileUploadApi | Chunked file upload (create slot → upload parts → finalize) |
| fileRevisions | FileRevisionsApi | Download file revision content |
| forms | FormsApi | Forms and form attachments |
| users | UsersApi | Company and project users |
| projectTemplates | ProjectTemplatesApi | Available project templates |
| inspectionPlans | InspectionPlansApi | Inspection plans, items, zones and registrations |
| testPlans | TestPlansApi | Test plans, items, zones and registrations |
| versionSets | VersionSetsApi | Version sets and version set files |
| workPackages | WorkPackagesApi | Work packages on a project |
ProjectsApi
| Method | HTTP | Path |
| ------------------------------------------- | ----- | -------------------------------------------------------------- |
| listProjects(params?) | GET | /5.1/projects |
| getProject(projectId) | GET | /5.0/projects/{projectId} |
| createProject(body) | POST | /5.0/projects |
| updateProject(projectId, body) | PATCH | /5.0/projects/{projectId} |
| listMetadataMappingsForProjects() | GET | /1.0/projects/metadata/1.0/mappings |
| listMetadataValuesForProjects(key) | GET | /1.0/projects/metadata/1.0/mappings/{key}/values |
| listProjectMetadata(projectId) | GET | /1.0/projects/{projectId}/metadata |
| listProjectMetadataMappings(projectId) | GET | /1.0/projects/{projectId}/metadata/1.0/mappings |
| listProjectMetadataValues(projectId, key) | GET | /1.0/projects/{projectId}/metadata/1.0/mappings/{key}/values |
CompaniesApi
| Method | HTTP | Path |
| -------------------------------------------------- | ----- | ------------------------------------------------- |
| listProjectCompanies(projectId, params?) | GET | /3.1/projects/{projectId}/companies |
| getProjectCompany(projectId, companyId) | GET | /3.0/projects/{projectId}/companies/{companyId} |
| createProjectCompany(projectId, body) | POST | /3.1/projects/{projectId}/companies |
| updateProjectCompany(projectId, companyId, body) | PATCH | /3.0/projects/{projectId}/companies/{companyId} |
CompanyCatalogApi
| Method | HTTP | Path |
| -------------------------------------------------- | ----- | --------------------------------------------------------------------------- |
| getCompanies(params?) | GET | /2.2/companyCatalog |
| getCompany(catalogCompanyId) | GET | /1.2/companyCatalog/{catalogCompanyId} |
| createCompany(body) | POST | /2.2/companyCatalog |
| updateCompany(catalogCompanyId, body) | PATCH | /2.1/companyCatalog/{catalogCompanyId} |
| listCompanyMetadata(catalogCompanyId) | GET | /1.0/companyCatalog/{catalogCompanyId}/metadata |
| listCompanyMetadataMappings(catalogCompanyId) | GET | /1.0/companyCatalog/{catalogCompanyId}/metadata/1.0/mappings |
| listCompanyMetadataValues(catalogCompanyId, key) | GET | /1.0/companyCatalog/{catalogCompanyId}/metadata/1.0/mappings/{key}/values |
| listMetadataMappingsForCompanies() | GET | /1.0/companyCatalog/metadata/1.0/mappings |
| listMetadataValuesForCompanies(key) | GET | /1.0/companyCatalog/metadata/1.0/mappings/{key}/values |
TasksApi
| Method | HTTP | Path |
| -------------------------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| getProjectTasks(projectId, params?) | GET | /5.2/projects/{projectId}/tasks |
| getAllProjectTasks(projectId, params?, verbose?) | GET (paginated) | /5.2/projects/{projectId}/tasks — collects all items via nextPage / bookmark; respects metadata.totalRemainingItems or metadata.totalItems (Python parity) |
| getTask(projectId, taskId) | GET | /3.3/projects/{projectId}/tasks/{taskId} |
| getProjectTaskChanges(projectId, params?) | GET | /2.2/projects/{projectId}/tasks/changes |
| getProjectTaskAttachments(projectId, params?) | GET | /1.1/projects/{projectId}/tasks/attachments |
Query params: pass OData options on getProjectTasks / getAllProjectTasks (for example $filter). Shorthand: typeId is translated to $filter=data/type/typeId eq '…' when $filter is not set. TasksApi.normalizeTaskParams applies the same rules if you build requests manually.
FileAreasApi
| Method | HTTP | Path |
| ------------------------------------ | ---- | --------------------------------------------------- |
| getFileAreas(projectId, params?) | GET | /5.1/projects/{projectId}/file_areas |
| getFileArea(projectId, fileAreaId) | GET | /1.0/projects/{projectId}/file_areas/{fileAreaId} |
FilesApi
Browse and paginated helpers use route version 6.1 for the file collection. getFile (one file by id) uses 5.0, as in the Dalux Build API.
| Method | HTTP | Path |
| ------------------------------------------------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------- |
| listFiles(projectId, fileAreaId, params?) | GET | /6.1/projects/{projectId}/file_areas/{fileAreaId}/files |
| getAllFiles(projectId, fileAreaId, params?, verbose?) | GET (paginated) | Same — all file items via bookmark / metadata.totalRemainingItems |
| getAllFilesInFolder(projectId, fileAreaId, folderId, params?, verbose?) | — | Uses getAllFiles then filters by data.folderId |
| getFile(projectId, fileAreaId, fileId, options?) | GET | /5.0/.../files/{fileId} — optional { download: true, savePath } streams to disk (adds downloadedFilePath) |
| downloadFileFromLink(downloadLink, fileName, savePath?) | GET | Direct download URL with X-API-KEY |
| bulkDownloadFolder(projectId, fileAreaId, folderId, savePath?, opts?) | — | Optional filenameKeywords, filenameKeywordsMatch (any / all), filenameExtensions, params, verbose |
| bulkDownloadByIds(projectId, fileAreaId, fileIds, savePath?, options?) | GET + download | Per-id getFile then stream from downloadLink |
| getFilePropertiesMapping(projectId, fileAreaId, fileId) | GET | /1.0/.../files/{fileId}/properties/1.0/mappings |
| getFilePropertyMappingValues(projectId, fileAreaId, filePropertyId) | GET | /1.0/.../files/properties/1.0/mappings/{filePropertyId}/values |
FoldersApi
| Method | HTTP | Path |
| ----------------------------------------------------------- | ---- | ---------------------------------------------------------------------- |
| listFolders(projectId, fileAreaId, params?) | GET | /5.1/projects/{projectId}/file_areas/{fileAreaId}/folders |
| getFolder(projectId, fileAreaId, folderId) | GET | /5.0/projects/{projectId}/file_areas/{fileAreaId}/folders/{folderId} |
| getFolderFilesProperties(projectId, fileAreaId, folderId) | GET | /1.0/.../folders/{folderId}/files/properties/1.0/mappings |
FileUploadApi
| Method | HTTP | Path |
| ---------------------------------------------------------- | ---- | ---------------------------------------------------------- |
| createUpload(projectId, fileAreaId, body) | POST | /1.0/projects/{projectId}/file_areas/{fileAreaId}/upload |
| uploadFilePart(projectId, fileAreaId, uploadGuid, chunk) | POST | /1.0/.../upload/{uploadGuid} |
| finishUpload(projectId, fileAreaId, uploadGuid, body) | POST | /2.0/.../upload/{uploadGuid}/finalize |
FileRevisionsApi
| Method | HTTP | Path |
| ----------------------------------------------------------------------- | ---- | ------------------------------------------------------------ |
| getFileRevisionContent(projectId, fileAreaId, fileId, fileRevisionId) | GET | /2.0/.../files/{fileId}/revisions/{fileRevisionId}/content |
FormsApi
| Method | HTTP | Path |
| ----------------------------------------------- | ---- | --------------------------------------------- |
| getProjectForms(projectId, params?) | GET | /2.1/projects/{projectId}/forms |
| getForm(projectId, formId) | GET | /1.2/projects/{projectId}/forms/{formId} |
| getProjectFormAttachments(projectId, params?) | GET | /2.1/projects/{projectId}/forms/attachments |
UsersApi
| Method | HTTP | Path |
| -------------------------------------- | ---- | ------------------------------------------ |
| getUser(userId) | GET | /1.1/users/{userId} |
| listProjectUsers(projectId, params?) | GET | /1.2/projects/{projectId}/users |
| getProjectUser(projectId, userId) | GET | /1.1/projects/{projectId}/users/{userId} |
ProjectTemplatesApi
| Method | HTTP | Path |
| ------------------------------- | ---- | ----------------------- |
| listProjectTemplates(params?) | GET | /1.1/projectTemplates |
InspectionPlansApi
| Method | HTTP | Path |
| ----------------------------------------------------- | ---- | ------------------------------------------------------- |
| listInspectionPlans(projectId, params?) | GET | /1.2/projects/{projectId}/inspectionPlans |
| listInspectionPlanItems(projectId, params?) | GET | /1.1/projects/{projectId}/inspectionPlanItems |
| listInspectionPlanItemZones(projectId, params?) | GET | /1.1/projects/{projectId}/inspectionPlanItemZones |
| listInspectionPlanRegistrations(projectId, params?) | GET | /2.1/projects/{projectId}/inspectionPlanRegistrations |
TestPlansApi
| Method | HTTP | Path |
| ----------------------------------------------- | ---- | ------------------------------------------------- |
| listTestPlans(projectId, params?) | GET | /1.2/projects/{projectId}/testPlans |
| listTestPlanItems(projectId, params?) | GET | /1.1/projects/{projectId}/testPlanItems |
| listTestPlanItemZones(projectId, params?) | GET | /1.1/projects/{projectId}/testPlanItemZones |
| listTestPlanRegistrations(projectId, params?) | GET | /1.1/projects/{projectId}/testPlanRegistrations |
VersionSetsApi
| Method | HTTP | Path |
| --------------------------------------------------------- | ---- | ---------------------------------------------------------------- |
| getVersionSets(projectId, params?) | GET | /2.1/projects/{projectId}/version_sets |
| getVersionSet(projectId, versionSetId) | GET | /2.0/projects/{projectId}/version_sets/{versionSetId} |
| listFileAreaVersionSets(projectId, fileAreaId, params?) | GET | /2.1/projects/{projectId}/file_areas/{fileAreaId}/version_sets |
| listVersionSetFiles(projectId, versionSetId, params?) | GET | /3.0/projects/{projectId}/version_sets/{versionSetId}/files |
WorkPackagesApi
| Method | HTTP | Path |
| -------------------------------------- | ---- | ---------------------------------------- |
| listWorkPackages(projectId, params?) | GET | /1.0/projects/{projectId}/workpackages |
Advanced Usage
Using individual API classes
You can also instantiate API classes directly with a shared ApiClient:
const {
Configuration,
ApiClient,
ProjectsApi,
TasksApi,
} = require("dalux-build-api");
const config = new Configuration({
baseUrl: "https://<your-company>.dalux.com/api",
apiKey: "YOUR_API_KEY",
});
const apiClient = new ApiClient(config);
const projects = new ProjectsApi(apiClient);
const tasks = new TasksApi(apiClient);Development
# Install dependencies
npm install
# Run tests with coverage
npm testMaintainer: npm releases
Automatic (push to main)
- Merge to
main(or push directly). CI must pass. - After both the Node and Python test jobs succeed, CI calls Publish npm Package via
workflow_call(same run as CI, so it does not depend onworkflow_run). - The publish job only runs when that push changes
package.json,package-lock.json,src/, ortest/. - Version bump uses the same rules as the Python publisher (commit message tokens), but the current semver is
max(python/pyproject.toml, package.json)so npm catches up when the Python package is ahead. - It runs tests again, publishes to npm, then pushes
chore: release vX.Y.Z [skip npm], tagvX.Y.Z, and a GitHub Release (unless the tag already exists).[skip npm]skips a second publish pass and skips CI on that sync commit.
Manual
- Actions → Publish npm Package → Run workflow for patch / minor / major (same test → publish → sync commit → tag → GitHub Release). The entry workflow is npm-publish.yml; it delegates to npm-publish-reusable.yml (GitHub requires
workflow_callin its own file). - GitHub Release (published) publishes the version already in
package.jsonat that tag (no version bump in the workflow).
Create a GitHub environment named npm with secret NPM_TOKEN. If pushes or releases from GITHUB_TOKEN are blocked, set RELEASE_PAT as described in python/README.md.
First publish and E404 on npm publish
If CI fails with 404 Not Found - PUT …/dalux-build-api and is not in this registry, the package does not exist on npm yet or your token is not allowed to create it.
- Classic Automation tokens only publish packages your account already maintains. They cannot create a new package name. Fix: use a granular access token with write access to the
@bruadamscope (or all packages), or runnpm publish --access publiconce locally while logged in as the owner, then switch CI back to an automation token. - Confirm the package is not taken by someone else: https://www.npmjs.com/package/dalux-build-api.
License
MIT
