dalux-build-api 1.1.0 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,58 +1,281 @@
1
- 'use strict';
2
-
3
- /**
4
- * API methods for folders within a file area.
5
- */
6
- class FoldersApi {
7
- /**
8
- * @param {import('../apiClient')} apiClient
9
- */
10
- constructor(apiClient) {
11
- this._client = apiClient;
12
- }
13
-
14
- /**
15
- * Browse all folders on the given project and file area.
16
- * GET /5.1/projects/{projectId}/file_areas/{fileAreaId}/folders
17
- * @param {string} projectId
18
- * @param {string} fileAreaId
19
- * @param {object} [params]
20
- * @returns {Promise<object>}
21
- */
22
- listFolders(projectId, fileAreaId, params = {}) {
23
- return this._client.get(
24
- `/5.1/projects/${projectId}/file_areas/${fileAreaId}/folders`,
25
- params,
26
- );
27
- }
28
-
29
- /**
30
- * Retrieve a specific folder.
31
- * GET /5.0/projects/{projectId}/file_areas/{fileAreaId}/folders/{folderId}
32
- * @param {string} projectId
33
- * @param {string} fileAreaId
34
- * @param {string} folderId
35
- * @returns {Promise<object>}
36
- */
37
- getFolder(projectId, fileAreaId, folderId) {
38
- return this._client.get(
39
- `/5.0/projects/${projectId}/file_areas/${fileAreaId}/folders/${folderId}`,
40
- );
41
- }
42
-
43
- /**
44
- * Retrieve all properties for each file type in a specific folder.
45
- * GET /1.0/projects/{projectId}/file_areas/{fileAreaId}/folders/{folderId}/files/properties/1.0/mappings
46
- * @param {string} projectId
47
- * @param {string} fileAreaId
48
- * @param {string} folderId
49
- * @returns {Promise<object>}
50
- */
51
- getFolderFilesProperties(projectId, fileAreaId, folderId) {
52
- return this._client.get(
53
- `/1.0/projects/${projectId}/file_areas/${fileAreaId}/folders/${folderId}/files/properties/1.0/mappings`,
54
- );
55
- }
56
- }
57
-
58
- module.exports = FoldersApi;
1
+ 'use strict';
2
+
3
+ const { paginate } = require('../utils/pagination');
4
+ const { findByField } = require('../utils/search');
5
+ const { validateProjectId, validateFileAreaId } = require('../utils/validation');
6
+ const { resolveFolderIdFromNamedPath } = require('../utils/pathResolver');
7
+
8
+ /**
9
+ * API methods for folders within a file area.
10
+ */
11
+ class FoldersApi {
12
+ /**
13
+ * @param {import('../apiClient')} apiClient
14
+ */
15
+ constructor(apiClient) {
16
+ this._client = apiClient;
17
+ }
18
+
19
+ /**
20
+ * Browse all folders on the given project and file area (single page).
21
+ * GET /5.1/projects/{projectId}/file_areas/{fileAreaId}/folders
22
+ * @param {string} projectId
23
+ * @param {string} fileAreaId
24
+ * @param {object} [params]
25
+ * @returns {Promise<object>}
26
+ */
27
+ listFolders(projectId, fileAreaId, params = {}) {
28
+ return this._client.get(
29
+ `/5.1/projects/${projectId}/file_areas/${fileAreaId}/folders`,
30
+ params,
31
+ );
32
+ }
33
+
34
+ /**
35
+ * Retrieve all folders by following bookmark pagination automatically.
36
+ * @param {string} projectId
37
+ * @param {string} fileAreaId
38
+ * @param {object} [params]
39
+ * @param {boolean} [verbose=false]
40
+ * @returns {Promise<object[]>} All folder items across all pages.
41
+ */
42
+ async getAllFolders(projectId, fileAreaId, params = {}, verbose = false) {
43
+ validateProjectId(projectId);
44
+ validateFileAreaId(fileAreaId);
45
+ const endpoint = `/5.1/projects/${projectId}/file_areas/${fileAreaId}/folders`;
46
+ return paginate(endpoint, this._client, params, verbose);
47
+ }
48
+
49
+ /**
50
+ * Retrieve a specific folder.
51
+ * GET /5.0/projects/{projectId}/file_areas/{fileAreaId}/folders/{folderId}
52
+ * @param {string} projectId
53
+ * @param {string} fileAreaId
54
+ * @param {string} folderId
55
+ * @returns {Promise<object>}
56
+ */
57
+ getFolder(projectId, fileAreaId, folderId) {
58
+ return this._client.get(
59
+ `/5.0/projects/${projectId}/file_areas/${fileAreaId}/folders/${folderId}`,
60
+ );
61
+ }
62
+
63
+ /**
64
+ * Get a folder using a full path starting with the file area name.
65
+ * e.g. "Files/4_Design/C07_Geometry"
66
+ * @param {string} projectId
67
+ * @param {string} path - Full path starting with file area name.
68
+ * @param {boolean} [verbose=false]
69
+ * @returns {Promise<object|null>} Folder response or null if not found.
70
+ */
71
+ async getFolderByPath(projectId, path, verbose = false) {
72
+ validateProjectId(projectId);
73
+ const { fileAreaId, folderId } = await resolveFolderIdFromNamedPath(
74
+ this._client, projectId, path, { verbose },
75
+ );
76
+ if (!fileAreaId || !folderId) return null;
77
+ return this.getFolder(projectId, fileAreaId, folderId);
78
+ }
79
+
80
+ /**
81
+ * Retrieve all properties for each file type in a specific folder.
82
+ * GET /1.0/projects/{projectId}/file_areas/{fileAreaId}/folders/{folderId}/files/properties/1.0/mappings
83
+ * @param {string} projectId
84
+ * @param {string} fileAreaId
85
+ * @param {string} folderId
86
+ * @returns {Promise<object>}
87
+ */
88
+ getFolderFilesProperties(projectId, fileAreaId, folderId) {
89
+ return this._client.get(
90
+ `/1.0/projects/${projectId}/file_areas/${fileAreaId}/folders/${folderId}/files/properties/1.0/mappings`,
91
+ );
92
+ }
93
+
94
+ /**
95
+ * Get a folder by name within a file area, optionally filtered by parent folder.
96
+ * @param {string} projectId
97
+ * @param {string} fileAreaId
98
+ * @param {string} folderName
99
+ * @param {string|null} [parentFolderId=null]
100
+ * @returns {Promise<object|null>} Folder item or null if not found.
101
+ */
102
+ async getFolderByName(projectId, fileAreaId, folderName, parentFolderId = null) {
103
+ validateProjectId(projectId);
104
+ validateFileAreaId(fileAreaId);
105
+ const allFolders = await this.getAllFolders(projectId, fileAreaId);
106
+ const folder = findByField(allFolders, 'folderName', folderName, (x) => x.data || x)
107
+ || findByField(allFolders, 'name', folderName, (x) => x.data || x);
108
+ if (!folder) return null;
109
+ if (parentFolderId != null) {
110
+ const data = folder.data || folder;
111
+ const pid = data.parentFolderId || data.parentId;
112
+ if (pid !== parentFolderId) return null;
113
+ }
114
+ return folder;
115
+ }
116
+
117
+ /**
118
+ * Resolve a folder path (e.g. "Folder1/Folder2") to a folder ID.
119
+ * Supports wildcard matching with * in path segments.
120
+ * @param {string} projectId
121
+ * @param {string} fileAreaId
122
+ * @param {string} folderPath - e.g. "Folder1/SubFolder" or a wildcard path ("*" matches any single segment)
123
+ * @param {boolean} [verbose=false]
124
+ * @returns {Promise<string|null>} Folder ID or null if not found.
125
+ */
126
+ async getFileAreaTreeByPath(projectId, fileAreaId, folderPath, verbose = false) {
127
+ const allFolders = await this.getAllFolders(projectId, fileAreaId);
128
+
129
+ const cleanPath = folderPath.replace(/^\/|\/$/g, '');
130
+ const pathParts = cleanPath.split('/').map((p) => p.trim()).filter(Boolean);
131
+ if (!pathParts.length) return null;
132
+
133
+ function getData(item) {
134
+ return item.data || item;
135
+ }
136
+ function getFid(item) {
137
+ const d = getData(item);
138
+ return d.folderId || d.id || null;
139
+ }
140
+ function getPid(item) {
141
+ const d = getData(item);
142
+ return d.parentFolderId || d.parentId || '';
143
+ }
144
+ function getName(item) {
145
+ const d = getData(item);
146
+ return d.folderName || d.name || '';
147
+ }
148
+
149
+ // Collect valid folder IDs
150
+ const validFolderIds = new Set(allFolders.map(getFid).filter(Boolean));
151
+ const fileAreaRootId = fileAreaId;
152
+
153
+ let candidateParentIds = new Set([fileAreaRootId, null, '']);
154
+
155
+ for (const segment of pathParts) {
156
+ const pattern = segment.toLowerCase();
157
+ const nextCandidates = new Set();
158
+ for (const item of allFolders) {
159
+ const fid = getFid(item);
160
+ const pid = getPid(item);
161
+ const name = getName(item).toLowerCase();
162
+ // The folder's effective parent: if pid is not in validFolderIds, treat as root
163
+ const effectivePid = validFolderIds.has(pid) ? pid : fileAreaRootId;
164
+ if (candidateParentIds.has(effectivePid) && _fnmatch(name, pattern)) {
165
+ if (fid) nextCandidates.add(fid);
166
+ }
167
+ }
168
+ if (!nextCandidates.size) {
169
+ if (verbose) console.log(`Folder segment '${segment}' not found`);
170
+ return null;
171
+ }
172
+ candidateParentIds = nextCandidates;
173
+ }
174
+
175
+ const result = [...candidateParentIds];
176
+ if (result.length === 1) return result[0];
177
+ if (result.length > 1) {
178
+ if (verbose) console.log(`Multiple folders match path '${folderPath}'`);
179
+ return result[0];
180
+ }
181
+ return null;
182
+ }
183
+
184
+ /**
185
+ * Build the complete folder+file tree for a file area.
186
+ * Fetches all folders (and optionally all files) and assembles them into a nested tree.
187
+ * When *filesApi* is provided, folders and files are fetched concurrently.
188
+ *
189
+ * Each node has the shape:
190
+ * ```
191
+ * { id, name, path, raw, children: [...], files: [...] }
192
+ * ```
193
+ * The returned root node represents the file-area root (id=null).
194
+ *
195
+ * @param {string} projectId
196
+ * @param {string} fileAreaId
197
+ * @param {object|null} [filesApi] - Optional FilesApi instance; when provided files are
198
+ * fetched in parallel and attached to their folder nodes.
199
+ * @param {boolean} [verbose=false]
200
+ * @returns {Promise<object>} Root tree node.
201
+ */
202
+ async getFileAreaTree(projectId, fileAreaId, filesApi = null, verbose = false) {
203
+ let allFolders, allFiles;
204
+
205
+ if (filesApi) {
206
+ [allFolders, allFiles] = await Promise.all([
207
+ this.getAllFolders(projectId, fileAreaId, {}, verbose),
208
+ filesApi.getAllFiles(projectId, fileAreaId, {}, verbose),
209
+ ]);
210
+ } else {
211
+ allFolders = await this.getAllFolders(projectId, fileAreaId, {}, verbose);
212
+ allFiles = [];
213
+ }
214
+
215
+ if (verbose) {
216
+ console.log(`Building tree: ${allFolders.length} folder(s), ${allFiles.length} file(s)`);
217
+ }
218
+
219
+ function fid(item) {
220
+ const d = item.data || item;
221
+ return d.folderId || d.id || null;
222
+ }
223
+ function pid(item) {
224
+ const d = item.data || item;
225
+ return d.parentFolderId || d.parentId || null;
226
+ }
227
+ function name(item) {
228
+ const d = item.data || item;
229
+ return d.folderName || d.name || fid(item) || '?';
230
+ }
231
+
232
+ // Build node map
233
+ const nodes = {};
234
+ for (const folder of allFolders) {
235
+ const id = fid(folder);
236
+ if (!id) continue;
237
+ nodes[id] = { id, name: name(folder), path: '', raw: folder, children: [], files: [] };
238
+ }
239
+
240
+ // Wire parent→child
241
+ const root = { id: null, name: fileAreaId, path: '', raw: null, children: [], files: [] };
242
+ const validIds = new Set(Object.keys(nodes));
243
+ for (const folder of allFolders) {
244
+ const id = fid(folder);
245
+ if (!id) continue;
246
+ const parentId = pid(folder);
247
+ const parent = (parentId && validIds.has(parentId)) ? nodes[parentId] : root;
248
+ parent.children.push(nodes[id]);
249
+ }
250
+
251
+ // Compute paths
252
+ function setPaths(node, parentPath) {
253
+ node.path = parentPath ? `${parentPath}/${node.name}` : node.name;
254
+ for (const child of node.children) setPaths(child, node.path);
255
+ }
256
+ for (const child of root.children) setPaths(child, '');
257
+
258
+ // Attach files to their folder nodes
259
+ for (const f of allFiles) {
260
+ const folderIdVal = (f.data || {}).folderId || f.folderId || null;
261
+ const target = (folderIdVal && nodes[folderIdVal]) ? nodes[folderIdVal] : root;
262
+ target.files.push(f);
263
+ }
264
+
265
+ return root;
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Simple fnmatch-style wildcard matching (only * is supported).
271
+ * @param {string} str
272
+ * @param {string} pattern
273
+ * @returns {boolean}
274
+ */
275
+ function _fnmatch(str, pattern) {
276
+ if (!pattern.includes('*')) return str === pattern;
277
+ const re = new RegExp('^' + pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') + '$');
278
+ return re.test(str);
279
+ }
280
+
281
+ module.exports = FoldersApi;
@@ -1,48 +1,48 @@
1
- 'use strict';
2
-
3
- /**
4
- * API methods for forms on a project.
5
- */
6
- class FormsApi {
7
- /**
8
- * @param {import('../apiClient')} apiClient
9
- */
10
- constructor(apiClient) {
11
- this._client = apiClient;
12
- }
13
-
14
- /**
15
- * Retrieve forms on a project.
16
- * GET /2.1/projects/{projectId}/forms
17
- * @param {string} projectId
18
- * @param {object} [params] - Optional filters (e.g. updatedAfter)
19
- * @returns {Promise<object>}
20
- */
21
- getProjectForms(projectId, params = {}) {
22
- return this._client.get(`/2.1/projects/${projectId}/forms`, params);
23
- }
24
-
25
- /**
26
- * Retrieve a specific form.
27
- * GET /1.2/projects/{projectId}/forms/{formId}
28
- * @param {string} projectId
29
- * @param {string} formId
30
- * @returns {Promise<object>}
31
- */
32
- getForm(projectId, formId) {
33
- return this._client.get(`/1.2/projects/${projectId}/forms/${formId}`);
34
- }
35
-
36
- /**
37
- * Retrieve attachments on forms on a project in incremental updates.
38
- * GET /2.1/projects/{projectId}/forms/attachments
39
- * @param {string} projectId
40
- * @param {object} [params] - Optional filters (e.g. updatedAfter)
41
- * @returns {Promise<object>}
42
- */
43
- getProjectFormAttachments(projectId, params = {}) {
44
- return this._client.get(`/2.1/projects/${projectId}/forms/attachments`, params);
45
- }
46
- }
47
-
48
- module.exports = FormsApi;
1
+ 'use strict';
2
+
3
+ /**
4
+ * API methods for forms on a project.
5
+ */
6
+ class FormsApi {
7
+ /**
8
+ * @param {import('../apiClient')} apiClient
9
+ */
10
+ constructor(apiClient) {
11
+ this._client = apiClient;
12
+ }
13
+
14
+ /**
15
+ * Retrieve forms on a project.
16
+ * GET /2.1/projects/{projectId}/forms
17
+ * @param {string} projectId
18
+ * @param {object} [params] - Optional filters (e.g. updatedAfter)
19
+ * @returns {Promise<object>}
20
+ */
21
+ getProjectForms(projectId, params = {}) {
22
+ return this._client.get(`/2.1/projects/${projectId}/forms`, params);
23
+ }
24
+
25
+ /**
26
+ * Retrieve a specific form.
27
+ * GET /1.2/projects/{projectId}/forms/{formId}
28
+ * @param {string} projectId
29
+ * @param {string} formId
30
+ * @returns {Promise<object>}
31
+ */
32
+ getForm(projectId, formId) {
33
+ return this._client.get(`/1.2/projects/${projectId}/forms/${formId}`);
34
+ }
35
+
36
+ /**
37
+ * Retrieve attachments on forms on a project in incremental updates.
38
+ * GET /2.1/projects/{projectId}/forms/attachments
39
+ * @param {string} projectId
40
+ * @param {object} [params] - Optional filters (e.g. updatedAfter)
41
+ * @returns {Promise<object>}
42
+ */
43
+ getProjectFormAttachments(projectId, params = {}) {
44
+ return this._client.get(`/2.1/projects/${projectId}/forms/attachments`, params);
45
+ }
46
+ }
47
+
48
+ module.exports = FormsApi;
@@ -1,62 +1,62 @@
1
- 'use strict';
2
-
3
- /**
4
- * API methods for inspection plans.
5
- */
6
- class InspectionPlansApi {
7
- /**
8
- * @param {import('../apiClient')} apiClient
9
- */
10
- constructor(apiClient) {
11
- this._client = apiClient;
12
- }
13
-
14
- /**
15
- * Browse all inspection plans on the given project.
16
- * GET /1.2/projects/{projectId}/inspectionPlans
17
- * @param {string} projectId
18
- * @param {object} [params]
19
- * @returns {Promise<object>}
20
- */
21
- listInspectionPlans(projectId, params = {}) {
22
- return this._client.get(`/1.2/projects/${projectId}/inspectionPlans`, params);
23
- }
24
-
25
- /**
26
- * Browse all inspection plan items on the given project.
27
- * GET /1.1/projects/{projectId}/inspectionPlanItems
28
- * @param {string} projectId
29
- * @param {object} [params]
30
- * @returns {Promise<object>}
31
- */
32
- listInspectionPlanItems(projectId, params = {}) {
33
- return this._client.get(`/1.1/projects/${projectId}/inspectionPlanItems`, params);
34
- }
35
-
36
- /**
37
- * Browse all inspection plan item zones on the given project.
38
- * GET /1.1/projects/{projectId}/inspectionPlanItemZones
39
- * @param {string} projectId
40
- * @param {object} [params]
41
- * @returns {Promise<object>}
42
- */
43
- listInspectionPlanItemZones(projectId, params = {}) {
44
- return this._client.get(`/1.1/projects/${projectId}/inspectionPlanItemZones`, params);
45
- }
46
-
47
- /**
48
- * Browse all inspection plan registrations on the given project.
49
- * GET /2.1/projects/{projectId}/inspectionPlanRegistrations
50
- * @param {string} projectId
51
- * @param {object} [params]
52
- * @returns {Promise<object>}
53
- */
54
- listInspectionPlanRegistrations(projectId, params = {}) {
55
- return this._client.get(
56
- `/2.1/projects/${projectId}/inspectionPlanRegistrations`,
57
- params,
58
- );
59
- }
60
- }
61
-
62
- module.exports = InspectionPlansApi;
1
+ 'use strict';
2
+
3
+ /**
4
+ * API methods for inspection plans.
5
+ */
6
+ class InspectionPlansApi {
7
+ /**
8
+ * @param {import('../apiClient')} apiClient
9
+ */
10
+ constructor(apiClient) {
11
+ this._client = apiClient;
12
+ }
13
+
14
+ /**
15
+ * Browse all inspection plans on the given project.
16
+ * GET /1.2/projects/{projectId}/inspectionPlans
17
+ * @param {string} projectId
18
+ * @param {object} [params]
19
+ * @returns {Promise<object>}
20
+ */
21
+ listInspectionPlans(projectId, params = {}) {
22
+ return this._client.get(`/1.2/projects/${projectId}/inspectionPlans`, params);
23
+ }
24
+
25
+ /**
26
+ * Browse all inspection plan items on the given project.
27
+ * GET /1.1/projects/{projectId}/inspectionPlanItems
28
+ * @param {string} projectId
29
+ * @param {object} [params]
30
+ * @returns {Promise<object>}
31
+ */
32
+ listInspectionPlanItems(projectId, params = {}) {
33
+ return this._client.get(`/1.1/projects/${projectId}/inspectionPlanItems`, params);
34
+ }
35
+
36
+ /**
37
+ * Browse all inspection plan item zones on the given project.
38
+ * GET /1.1/projects/{projectId}/inspectionPlanItemZones
39
+ * @param {string} projectId
40
+ * @param {object} [params]
41
+ * @returns {Promise<object>}
42
+ */
43
+ listInspectionPlanItemZones(projectId, params = {}) {
44
+ return this._client.get(`/1.1/projects/${projectId}/inspectionPlanItemZones`, params);
45
+ }
46
+
47
+ /**
48
+ * Browse all inspection plan registrations on the given project.
49
+ * GET /2.1/projects/{projectId}/inspectionPlanRegistrations
50
+ * @param {string} projectId
51
+ * @param {object} [params]
52
+ * @returns {Promise<object>}
53
+ */
54
+ listInspectionPlanRegistrations(projectId, params = {}) {
55
+ return this._client.get(
56
+ `/2.1/projects/${projectId}/inspectionPlanRegistrations`,
57
+ params,
58
+ );
59
+ }
60
+ }
61
+
62
+ module.exports = InspectionPlansApi;
@@ -1,25 +1,25 @@
1
- 'use strict';
2
-
3
- /**
4
- * API methods for project templates.
5
- */
6
- class ProjectTemplatesApi {
7
- /**
8
- * @param {import('../apiClient')} apiClient
9
- */
10
- constructor(apiClient) {
11
- this._client = apiClient;
12
- }
13
-
14
- /**
15
- * Get all available project templates on the company profile.
16
- * GET /1.1/projectTemplates
17
- * @param {object} [params]
18
- * @returns {Promise<object>}
19
- */
20
- listProjectTemplates(params = {}) {
21
- return this._client.get('/1.1/projectTemplates', params);
22
- }
23
- }
24
-
25
- module.exports = ProjectTemplatesApi;
1
+ 'use strict';
2
+
3
+ /**
4
+ * API methods for project templates.
5
+ */
6
+ class ProjectTemplatesApi {
7
+ /**
8
+ * @param {import('../apiClient')} apiClient
9
+ */
10
+ constructor(apiClient) {
11
+ this._client = apiClient;
12
+ }
13
+
14
+ /**
15
+ * Get all available project templates on the company profile.
16
+ * GET /1.1/projectTemplates
17
+ * @param {object} [params]
18
+ * @returns {Promise<object>}
19
+ */
20
+ listProjectTemplates(params = {}) {
21
+ return this._client.get('/1.1/projectTemplates', params);
22
+ }
23
+ }
24
+
25
+ module.exports = ProjectTemplatesApi;