dalux-build-api 1.1.3 → 2.0.0
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.
- package/LICENSE +21 -21
- package/README.md +404 -365
- package/package.json +47 -46
- package/src/api/CompaniesApi.js +67 -60
- package/src/api/CompanyCatalogApi.js +129 -108
- package/src/api/FileAreasApi.js +57 -37
- package/src/api/FileRevisionsApi.js +31 -31
- package/src/api/FileUploadApi.js +64 -64
- package/src/api/FilesApi.js +701 -297
- package/src/api/FoldersApi.js +283 -58
- package/src/api/FormsApi.js +53 -48
- package/src/api/InspectionPlansApi.js +66 -62
- package/src/api/ProjectTemplatesApi.js +25 -25
- package/src/api/ProjectsApi.js +127 -106
- package/src/api/TasksApi.js +193 -161
- package/src/api/TestPlansApi.js +63 -59
- package/src/api/UsersApi.js +52 -47
- package/src/api/VersionSetsApi.js +75 -67
- package/src/api/WorkPackagesApi.js +30 -26
- package/src/apiClient.js +139 -75
- package/src/configuration.js +39 -24
- package/src/index.js +133 -92
- package/src/models/common.js +22 -0
- package/src/models/companies/index.js +14 -0
- package/src/models/companyCatalog/index.js +19 -0
- package/src/models/convert.js +44 -0
- package/src/models/fileAreas/index.js +20 -0
- package/src/models/fileRevisions/index.js +12 -0
- package/src/models/fileUpload/index.js +12 -0
- package/src/models/files/index.js +97 -0
- package/src/models/folders/index.js +20 -0
- package/src/models/forms/index.js +19 -0
- package/src/models/helpers.js +62 -0
- package/src/models/index.js +148 -0
- package/src/models/inspectionPlans/index.js +18 -0
- package/src/models/projectTemplates/index.js +11 -0
- package/src/models/projects/index.js +57 -0
- package/src/models/tasks/index.js +105 -0
- package/src/models/testPlans/index.js +17 -0
- package/src/models/users/index.js +29 -0
- package/src/models/versionSets/index.js +22 -0
- package/src/models/workPackages/index.js +19 -0
- package/src/utils/errors.js +45 -0
- package/src/utils/index.js +26 -0
- package/src/utils/pagination.js +82 -0
- package/src/utils/pathResolver.js +124 -0
- package/src/utils/search.js +61 -0
- package/src/utils/validation.js +36 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zod schemas for Dalux Build API responses. Mirrors the public surface of
|
|
5
|
+
* python/dalux_build/models/__init__.py, with a `Schema` suffix on every
|
|
6
|
+
* export name (these are zod schema objects, not constructible classes).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { LinkSchema, MetadataSchema } = require('./common');
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
ProjectSchema,
|
|
13
|
+
ProjectModuleSchema,
|
|
14
|
+
ProjectMetadataSchema,
|
|
15
|
+
ProjectTemplateSchema,
|
|
16
|
+
ProjectCompanySchema,
|
|
17
|
+
ProjectsListResponseSchema,
|
|
18
|
+
ProjectResponseSchema,
|
|
19
|
+
} = require('./projects');
|
|
20
|
+
|
|
21
|
+
const { FileAreaSchema, FileAreasListResponseSchema, FileAreaResponseSchema } = require('./fileAreas');
|
|
22
|
+
|
|
23
|
+
const { FolderSchema, FoldersListResponseSchema, FolderResponseSchema } = require('./folders');
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
FileSchema,
|
|
27
|
+
ReferenceSchema,
|
|
28
|
+
FileNameFilterSchema,
|
|
29
|
+
FileIntegerPropertySchema,
|
|
30
|
+
FileDatePropertySchema,
|
|
31
|
+
FileTextPropertySchema,
|
|
32
|
+
FileReferencePropertySchema,
|
|
33
|
+
FilePropertyFieldSchema,
|
|
34
|
+
FilesListResponseSchema,
|
|
35
|
+
FileResponseSchema,
|
|
36
|
+
} = require('./files');
|
|
37
|
+
|
|
38
|
+
const { VersionSetSchema, VersionSetsListResponseSchema, VersionSetResponseSchema } = require('./versionSets');
|
|
39
|
+
|
|
40
|
+
const { UserSchema, ProjectUserSchema, UsersListResponseSchema, UserResponseSchema } = require('./users');
|
|
41
|
+
|
|
42
|
+
const { CompaniesListResponseSchema, CompanyResponseSchema } = require('./companies');
|
|
43
|
+
|
|
44
|
+
const { CompanyCatalogListResponseSchema, CompanyCatalogResponseSchema } = require('./companyCatalog');
|
|
45
|
+
|
|
46
|
+
const { InspectionPlanSchema, InspectionPlansListResponseSchema } = require('./inspectionPlans');
|
|
47
|
+
|
|
48
|
+
const { TestPlanSchema, TestPlansListResponseSchema } = require('./testPlans');
|
|
49
|
+
|
|
50
|
+
const { FormSchema, FormsListResponseSchema, FormResponseSchema } = require('./forms');
|
|
51
|
+
|
|
52
|
+
const {
|
|
53
|
+
TaskSchema,
|
|
54
|
+
TaskAttachmentSchema,
|
|
55
|
+
TaskChangeSchema,
|
|
56
|
+
TaskChangeActorSchema,
|
|
57
|
+
TaskChangeFieldsSchema,
|
|
58
|
+
TaskChangeLocationSchema,
|
|
59
|
+
TaskListParamsSchema,
|
|
60
|
+
TasksListResponseSchema,
|
|
61
|
+
TaskResponseSchema,
|
|
62
|
+
TaskChangeResponseSchema,
|
|
63
|
+
TaskChangesSchema,
|
|
64
|
+
TaskAttachmentsListResponseSchema,
|
|
65
|
+
} = require('./tasks');
|
|
66
|
+
|
|
67
|
+
const { FileRevisionSchema } = require('./fileRevisions');
|
|
68
|
+
const { FileUploadSchema } = require('./fileUpload');
|
|
69
|
+
const { WorkPackageSchema, WorkPackagesListResponseSchema } = require('./workPackages');
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
// Base
|
|
73
|
+
LinkSchema,
|
|
74
|
+
MetadataSchema,
|
|
75
|
+
// Projects
|
|
76
|
+
ProjectSchema,
|
|
77
|
+
ProjectModuleSchema,
|
|
78
|
+
ProjectMetadataSchema,
|
|
79
|
+
ProjectTemplateSchema,
|
|
80
|
+
ProjectCompanySchema,
|
|
81
|
+
ProjectsListResponseSchema,
|
|
82
|
+
ProjectResponseSchema,
|
|
83
|
+
// File Areas
|
|
84
|
+
FileAreaSchema,
|
|
85
|
+
FileAreasListResponseSchema,
|
|
86
|
+
FileAreaResponseSchema,
|
|
87
|
+
// Folders
|
|
88
|
+
FolderSchema,
|
|
89
|
+
FoldersListResponseSchema,
|
|
90
|
+
FolderResponseSchema,
|
|
91
|
+
// Files
|
|
92
|
+
FileSchema,
|
|
93
|
+
ReferenceSchema,
|
|
94
|
+
FileNameFilterSchema,
|
|
95
|
+
FileIntegerPropertySchema,
|
|
96
|
+
FileDatePropertySchema,
|
|
97
|
+
FileTextPropertySchema,
|
|
98
|
+
FileReferencePropertySchema,
|
|
99
|
+
FilePropertyFieldSchema,
|
|
100
|
+
FilesListResponseSchema,
|
|
101
|
+
FileResponseSchema,
|
|
102
|
+
// Version Sets
|
|
103
|
+
VersionSetSchema,
|
|
104
|
+
VersionSetsListResponseSchema,
|
|
105
|
+
VersionSetResponseSchema,
|
|
106
|
+
// Users
|
|
107
|
+
UserSchema,
|
|
108
|
+
ProjectUserSchema,
|
|
109
|
+
UsersListResponseSchema,
|
|
110
|
+
UserResponseSchema,
|
|
111
|
+
// Companies
|
|
112
|
+
CompaniesListResponseSchema,
|
|
113
|
+
CompanyResponseSchema,
|
|
114
|
+
// Company Catalog
|
|
115
|
+
CompanyCatalogListResponseSchema,
|
|
116
|
+
CompanyCatalogResponseSchema,
|
|
117
|
+
// Inspection Plans
|
|
118
|
+
InspectionPlanSchema,
|
|
119
|
+
InspectionPlansListResponseSchema,
|
|
120
|
+
// Test Plans
|
|
121
|
+
TestPlanSchema,
|
|
122
|
+
TestPlansListResponseSchema,
|
|
123
|
+
// Forms
|
|
124
|
+
FormSchema,
|
|
125
|
+
FormsListResponseSchema,
|
|
126
|
+
FormResponseSchema,
|
|
127
|
+
// Tasks
|
|
128
|
+
TaskSchema,
|
|
129
|
+
TaskAttachmentSchema,
|
|
130
|
+
TaskChangeSchema,
|
|
131
|
+
TaskChangeActorSchema,
|
|
132
|
+
TaskChangeFieldsSchema,
|
|
133
|
+
TaskChangeLocationSchema,
|
|
134
|
+
TaskListParamsSchema,
|
|
135
|
+
TasksListResponseSchema,
|
|
136
|
+
TaskResponseSchema,
|
|
137
|
+
TaskChangeResponseSchema,
|
|
138
|
+
TaskChangesSchema,
|
|
139
|
+
TaskAttachmentsListResponseSchema,
|
|
140
|
+
// Project Templates (same ProjectTemplateSchema as Projects, re-exported above)
|
|
141
|
+
// File Revisions
|
|
142
|
+
FileRevisionSchema,
|
|
143
|
+
// File Upload
|
|
144
|
+
FileUploadSchema,
|
|
145
|
+
// Work Packages
|
|
146
|
+
WorkPackageSchema,
|
|
147
|
+
WorkPackagesListResponseSchema,
|
|
148
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Mirrors models/inspection_plans/models.py::InspectionPlan — an empty
|
|
8
|
+
* placeholder in Python, so list items stay untyped (unwrapped but
|
|
9
|
+
* otherwise unvalidated).
|
|
10
|
+
*/
|
|
11
|
+
const InspectionPlanSchema = z.any();
|
|
12
|
+
|
|
13
|
+
const InspectionPlansListResponseSchema = listResponseSchema(InspectionPlanSchema);
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
InspectionPlanSchema,
|
|
17
|
+
InspectionPlansListResponseSchema,
|
|
18
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ProjectTemplateSchema } = require('../projects');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mirrors models/project_templates/models.py::ProjectTemplate — identical
|
|
7
|
+
* shape to projects/models.py::ProjectTemplate, so it's reused rather than
|
|
8
|
+
* duplicated. listProjectTemplates returns raw/unmodeled data in Python too
|
|
9
|
+
* (company-wide endpoint), so no response wrapper is defined here.
|
|
10
|
+
*/
|
|
11
|
+
module.exports = { ProjectTemplateSchema };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/projects/models.py::ProjectModule (empty placeholder, passthrough). */
|
|
7
|
+
const ProjectModuleSchema = z.object({}).passthrough();
|
|
8
|
+
|
|
9
|
+
/** Mirrors models/projects/models.py::Project. Note: `type` is the real JSON key (Python aliases project_type -> "type"). */
|
|
10
|
+
const ProjectSchema = z.object({
|
|
11
|
+
projectId: z.string(),
|
|
12
|
+
projectName: z.string(),
|
|
13
|
+
type: z.string().nullish(),
|
|
14
|
+
projectTemplateId: z.string().nullish(),
|
|
15
|
+
address: z.string().nullish(),
|
|
16
|
+
number: z.string().nullish(),
|
|
17
|
+
created: z.string().nullish(),
|
|
18
|
+
closing: z.string().nullish(),
|
|
19
|
+
modules: z.array(ProjectModuleSchema).nullish(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/** Mirrors models/projects/models.py::ProjectMetadata. */
|
|
23
|
+
const ProjectMetadataSchema = z.object({
|
|
24
|
+
key: z.string(),
|
|
25
|
+
value: z.string().nullish(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/** Mirrors models/projects/models.py::ProjectTemplate (also duplicated in project_templates/models.py — same shape). */
|
|
29
|
+
const ProjectTemplateSchema = z.object({
|
|
30
|
+
projectTemplateId: z.string(),
|
|
31
|
+
name: z.string(),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/** Mirrors models/projects/models.py::ProjectCompany. */
|
|
35
|
+
const ProjectCompanySchema = z.object({
|
|
36
|
+
companyId: z.string().nullish(),
|
|
37
|
+
name: z.string().nullish(),
|
|
38
|
+
vatNumber: z.string().nullish(),
|
|
39
|
+
address: z.string().nullish(),
|
|
40
|
+
city: z.string().nullish(),
|
|
41
|
+
postalCode: z.string().nullish(),
|
|
42
|
+
country: z.string().nullish(),
|
|
43
|
+
catalogCompanyId: z.string().nullish(),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const ProjectsListResponseSchema = listResponseSchema(ProjectSchema);
|
|
47
|
+
const ProjectResponseSchema = singleResponseSchema(ProjectSchema);
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
ProjectModuleSchema,
|
|
51
|
+
ProjectSchema,
|
|
52
|
+
ProjectMetadataSchema,
|
|
53
|
+
ProjectTemplateSchema,
|
|
54
|
+
ProjectCompanySchema,
|
|
55
|
+
ProjectsListResponseSchema,
|
|
56
|
+
ProjectResponseSchema,
|
|
57
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/tasks/models.py::Task (extra="allow" -> passthrough; only taskId is typed). */
|
|
7
|
+
const TaskSchema = z.object({
|
|
8
|
+
taskId: z.string().nullish(),
|
|
9
|
+
}).passthrough();
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Mirrors models/tasks/models.py::TaskListParams. Field names are the
|
|
13
|
+
* actual OData query keys (matches what src/api/TasksApi.js's
|
|
14
|
+
* normalizeTaskParams reads/writes) rather than Python's snake_case
|
|
15
|
+
* attribute names, since JS has no alias layer to bridge the two. These are
|
|
16
|
+
* developer-supplied query params (not API responses), so plain `.optional()`
|
|
17
|
+
* is fine.
|
|
18
|
+
*/
|
|
19
|
+
const TaskListParamsSchema = z.object({
|
|
20
|
+
typeId: z.string().optional(),
|
|
21
|
+
$filter: z.string().optional(),
|
|
22
|
+
$select: z.string().optional(),
|
|
23
|
+
$orderby: z.string().optional(),
|
|
24
|
+
$top: z.number().optional(),
|
|
25
|
+
$skip: z.number().optional(),
|
|
26
|
+
bookmark: z.string().optional(),
|
|
27
|
+
}).passthrough();
|
|
28
|
+
|
|
29
|
+
/** Mirrors models/tasks/models.py::TaskChangeActor. */
|
|
30
|
+
const TaskChangeActorSchema = z.object({
|
|
31
|
+
userId: z.string().nullish(),
|
|
32
|
+
roleId: z.string().nullish(),
|
|
33
|
+
roleName: z.string().nullish(),
|
|
34
|
+
userName: z.string().nullish(),
|
|
35
|
+
name: z.string().nullish(),
|
|
36
|
+
}).passthrough();
|
|
37
|
+
|
|
38
|
+
/** Mirrors models/tasks/models.py::TaskChangeLocation (empty passthrough). */
|
|
39
|
+
const TaskChangeLocationSchema = z.object({}).passthrough();
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Preprocesses the deadline field the same way Python's
|
|
43
|
+
* `normalize_deadline` field_validator does: unwraps API payloads where
|
|
44
|
+
* deadline is returned as an object instead of a bare string.
|
|
45
|
+
*/
|
|
46
|
+
const deadlineSchema = z.preprocess((value) => {
|
|
47
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
48
|
+
if (value.empty === true) return undefined;
|
|
49
|
+
if ('value' in value) return value.value;
|
|
50
|
+
if ('date' in value) return value.date;
|
|
51
|
+
if ('datetime' in value) return value.datetime;
|
|
52
|
+
}
|
|
53
|
+
return value;
|
|
54
|
+
}, z.string().nullish());
|
|
55
|
+
|
|
56
|
+
/** Mirrors models/tasks/models.py::TaskChangeFields. */
|
|
57
|
+
const TaskChangeFieldsSchema = z.object({
|
|
58
|
+
currentResponsible: TaskChangeActorSchema.nullish(),
|
|
59
|
+
assignedTo: TaskChangeActorSchema.nullish(),
|
|
60
|
+
title: z.string().nullish(),
|
|
61
|
+
deadline: deadlineSchema,
|
|
62
|
+
status: z.string().nullish(),
|
|
63
|
+
modifiedBy: TaskChangeActorSchema.nullish(),
|
|
64
|
+
userDefinedFields: z.record(z.any()).nullish(),
|
|
65
|
+
workpackageId: z.string().nullish(),
|
|
66
|
+
location: TaskChangeLocationSchema.nullish(),
|
|
67
|
+
}).passthrough();
|
|
68
|
+
|
|
69
|
+
/** Mirrors models/tasks/models.py::TaskChange. */
|
|
70
|
+
const TaskChangeSchema = z.object({
|
|
71
|
+
taskId: z.string(),
|
|
72
|
+
description: z.string().nullish(),
|
|
73
|
+
timestamp: z.string(),
|
|
74
|
+
action: z.string(),
|
|
75
|
+
fields: TaskChangeFieldsSchema.nullish(),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
/** Mirrors models/tasks/models.py::TaskAttachment. */
|
|
79
|
+
const TaskAttachmentSchema = z.object({
|
|
80
|
+
attachmentId: z.string().nullish(),
|
|
81
|
+
taskId: z.string().nullish(),
|
|
82
|
+
fileId: z.string().nullish(),
|
|
83
|
+
}).passthrough();
|
|
84
|
+
|
|
85
|
+
const TasksListResponseSchema = listResponseSchema(TaskSchema);
|
|
86
|
+
const TaskResponseSchema = singleResponseSchema(TaskSchema);
|
|
87
|
+
const TaskChangeResponseSchema = singleResponseSchema(TaskChangeSchema);
|
|
88
|
+
/** Bare-list payloads (`[...]` instead of `{items: [...]}`) are handled by listResponseSchema's preprocessor. */
|
|
89
|
+
const TaskChangesSchema = listResponseSchema(TaskChangeSchema);
|
|
90
|
+
const TaskAttachmentsListResponseSchema = listResponseSchema(TaskAttachmentSchema);
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
TaskSchema,
|
|
94
|
+
TaskListParamsSchema,
|
|
95
|
+
TaskChangeActorSchema,
|
|
96
|
+
TaskChangeLocationSchema,
|
|
97
|
+
TaskChangeFieldsSchema,
|
|
98
|
+
TaskChangeSchema,
|
|
99
|
+
TaskAttachmentSchema,
|
|
100
|
+
TasksListResponseSchema,
|
|
101
|
+
TaskResponseSchema,
|
|
102
|
+
TaskChangeResponseSchema,
|
|
103
|
+
TaskChangesSchema,
|
|
104
|
+
TaskAttachmentsListResponseSchema,
|
|
105
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Mirrors models/test_plans/models.py::TestPlan — empty placeholder in
|
|
8
|
+
* Python, so list items stay untyped.
|
|
9
|
+
*/
|
|
10
|
+
const TestPlanSchema = z.any();
|
|
11
|
+
|
|
12
|
+
const TestPlansListResponseSchema = listResponseSchema(TestPlanSchema);
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
TestPlanSchema,
|
|
16
|
+
TestPlansListResponseSchema,
|
|
17
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/users/models.py::User. */
|
|
7
|
+
const UserSchema = z.object({
|
|
8
|
+
userId: z.string(),
|
|
9
|
+
userType: z.string(),
|
|
10
|
+
email: z.string().email(),
|
|
11
|
+
firstName: z.string().nullish(),
|
|
12
|
+
lastName: z.string().nullish(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/** Mirrors models/users/models.py::ProjectUser (User + companyId). */
|
|
16
|
+
const ProjectUserSchema = UserSchema.extend({
|
|
17
|
+
companyId: z.string().nullish(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const UsersListResponseSchema = listResponseSchema(ProjectUserSchema);
|
|
21
|
+
/** Single-user response wraps User, not ProjectUser — matches Python. */
|
|
22
|
+
const UserResponseSchema = singleResponseSchema(UserSchema);
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
UserSchema,
|
|
26
|
+
ProjectUserSchema,
|
|
27
|
+
UsersListResponseSchema,
|
|
28
|
+
UserResponseSchema,
|
|
29
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/version_sets/models.py::VersionSet. */
|
|
7
|
+
const VersionSetSchema = z.object({
|
|
8
|
+
versionSetId: z.string(),
|
|
9
|
+
name: z.string(),
|
|
10
|
+
description: z.string().nullish(),
|
|
11
|
+
status: z.string().nullish(),
|
|
12
|
+
fileAreaId: z.string(),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const VersionSetsListResponseSchema = listResponseSchema(VersionSetSchema);
|
|
16
|
+
const VersionSetResponseSchema = singleResponseSchema(VersionSetSchema);
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
VersionSetSchema,
|
|
20
|
+
VersionSetsListResponseSchema,
|
|
21
|
+
VersionSetResponseSchema,
|
|
22
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/work_packages/models.py::WorkPackage (extra="allow" -> passthrough). */
|
|
7
|
+
const WorkPackageSchema = z.object({
|
|
8
|
+
workpackageId: z.string().nullish(),
|
|
9
|
+
companyId: z.string().nullish(),
|
|
10
|
+
name: z.string().nullish(),
|
|
11
|
+
}).passthrough();
|
|
12
|
+
|
|
13
|
+
/** No single-item response class in Python. */
|
|
14
|
+
const WorkPackagesListResponseSchema = listResponseSchema(WorkPackageSchema);
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
WorkPackageSchema,
|
|
18
|
+
WorkPackagesListResponseSchema,
|
|
19
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base exception for all Dalux API errors.
|
|
5
|
+
*/
|
|
6
|
+
class DaluxError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = this.constructor.name;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resource not found (HTTP 404).
|
|
15
|
+
*/
|
|
16
|
+
class NotFoundError extends DaluxError {}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* API request failed (4xx / 5xx other than 401, 404, 429).
|
|
20
|
+
*/
|
|
21
|
+
class ApiError extends DaluxError {}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Input validation failed.
|
|
25
|
+
*/
|
|
26
|
+
class ValidationError extends DaluxError {}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Authentication failed (HTTP 401).
|
|
30
|
+
*/
|
|
31
|
+
class AuthenticationError extends DaluxError {}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Rate limit exceeded (HTTP 429).
|
|
35
|
+
*/
|
|
36
|
+
class RateLimitError extends DaluxError {}
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
DaluxError,
|
|
40
|
+
NotFoundError,
|
|
41
|
+
ApiError,
|
|
42
|
+
ValidationError,
|
|
43
|
+
AuthenticationError,
|
|
44
|
+
RateLimitError,
|
|
45
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { DaluxError, NotFoundError, ApiError, ValidationError, AuthenticationError, RateLimitError } = require('./errors');
|
|
4
|
+
const { hasNextPage, getNextBookmark, paginate } = require('./pagination');
|
|
5
|
+
const { findByField, findAllByField } = require('./search');
|
|
6
|
+
const { validateProjectId, validateFileAreaId, validateFolderId } = require('./validation');
|
|
7
|
+
const { resolveFileAreaByName, resolveFolderIdFromNamedPath } = require('./pathResolver');
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
DaluxError,
|
|
11
|
+
NotFoundError,
|
|
12
|
+
ApiError,
|
|
13
|
+
ValidationError,
|
|
14
|
+
AuthenticationError,
|
|
15
|
+
RateLimitError,
|
|
16
|
+
hasNextPage,
|
|
17
|
+
getNextBookmark,
|
|
18
|
+
paginate,
|
|
19
|
+
findByField,
|
|
20
|
+
findAllByField,
|
|
21
|
+
validateProjectId,
|
|
22
|
+
validateFileAreaId,
|
|
23
|
+
validateFolderId,
|
|
24
|
+
resolveFileAreaByName,
|
|
25
|
+
resolveFolderIdFromNamedPath,
|
|
26
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check whether an API response has a next page link.
|
|
5
|
+
* @param {object} response
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
function hasNextPage(response) {
|
|
9
|
+
if (!response) return false;
|
|
10
|
+
const links = response.links || [];
|
|
11
|
+
return links.some((l) => l.rel === 'nextPage');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extract the bookmark for the next page from an API response.
|
|
16
|
+
* @param {object} response
|
|
17
|
+
* @returns {string|null}
|
|
18
|
+
*/
|
|
19
|
+
function getNextBookmark(response) {
|
|
20
|
+
const links = (response && response.links) || [];
|
|
21
|
+
const nextLink = links.find((l) => l.rel === 'nextPage');
|
|
22
|
+
if (!nextLink) return null;
|
|
23
|
+
try {
|
|
24
|
+
return new URL(nextLink.href).searchParams.get('bookmark');
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Generic pagination handler: follows bookmark pages until exhausted.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} endpoint - API path.
|
|
34
|
+
* @param {object} client - ApiClient instance.
|
|
35
|
+
* @param {object} [params] - Base query parameters.
|
|
36
|
+
* @param {boolean} [verbose=false] - Log progress to console.
|
|
37
|
+
* @param {string} [itemAccessor='items'] - Key to read items from each response.
|
|
38
|
+
* @returns {Promise<any[]>} All items across all pages.
|
|
39
|
+
*/
|
|
40
|
+
async function paginate(endpoint, client, params = {}, verbose = false, itemAccessor = 'items') {
|
|
41
|
+
const allItems = [];
|
|
42
|
+
let currentParams = { ...params };
|
|
43
|
+
let pageCount = 0;
|
|
44
|
+
const seenBookmarks = new Set();
|
|
45
|
+
|
|
46
|
+
while (true) {
|
|
47
|
+
pageCount += 1;
|
|
48
|
+
const response = await client.get(endpoint, currentParams);
|
|
49
|
+
if (!response) break;
|
|
50
|
+
|
|
51
|
+
const items = response[itemAccessor] || [];
|
|
52
|
+
allItems.push(...items);
|
|
53
|
+
|
|
54
|
+
if (verbose) {
|
|
55
|
+
const meta = response.metadata || {};
|
|
56
|
+
const remaining = meta.totalRemainingItems ?? 0;
|
|
57
|
+
console.log(
|
|
58
|
+
`Page ${pageCount}: ${items.length} items, Total: ${allItems.length}, Remaining: ${remaining}`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!hasNextPage(response)) break;
|
|
63
|
+
|
|
64
|
+
const bookmark = getNextBookmark(response);
|
|
65
|
+
if (!bookmark) break;
|
|
66
|
+
if (seenBookmarks.has(bookmark)) {
|
|
67
|
+
if (verbose) {
|
|
68
|
+
console.log(`Detected duplicate bookmark '${bookmark}', stopping pagination to prevent infinite loop`);
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
seenBookmarks.add(bookmark);
|
|
73
|
+
currentParams = { ...params, bookmark };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (verbose) {
|
|
77
|
+
console.log(`Pagination complete. Total items retrieved: ${allItems.length}`);
|
|
78
|
+
}
|
|
79
|
+
return allItems;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = { hasNextPage, getNextBookmark, paginate };
|