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
package/src/configuration.js
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Load .env file when dotenv is available (optional peer dep)
|
|
4
|
+
try {
|
|
5
|
+
require('dotenv').config();
|
|
6
|
+
} catch (_) { /* dotenv not installed – skip */ }
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for the Dalux Build API client.
|
|
10
|
+
*
|
|
11
|
+
* When *baseUrl* or *apiKey* are not provided they are read from the
|
|
12
|
+
* environment variables ``DALUX_BASE_URL`` and ``DALUX_API_KEY`` respectively,
|
|
13
|
+
* matching the behaviour of the Python client.
|
|
14
|
+
*/
|
|
15
|
+
class Configuration {
|
|
16
|
+
/**
|
|
17
|
+
* @param {object} [options]
|
|
18
|
+
* @param {string} [options.baseUrl] - The API base URL provided by Dalux
|
|
19
|
+
* (e.g. ``https://<company>.dalux.com/api``).
|
|
20
|
+
* Falls back to the ``DALUX_BASE_URL`` environment variable.
|
|
21
|
+
* @param {string} [options.apiKey] - Your company-specific X-API-KEY.
|
|
22
|
+
* Falls back to the ``DALUX_API_KEY`` environment variable.
|
|
23
|
+
*/
|
|
24
|
+
constructor({ baseUrl, apiKey } = {}) {
|
|
25
|
+
const resolvedBaseUrl = baseUrl || process.env.DALUX_BASE_URL;
|
|
26
|
+
const resolvedApiKey = apiKey || process.env.DALUX_API_KEY;
|
|
27
|
+
|
|
28
|
+
if (!resolvedBaseUrl) {
|
|
29
|
+
throw new Error('baseUrl is required (or set DALUX_BASE_URL env var)');
|
|
30
|
+
}
|
|
31
|
+
if (!resolvedApiKey) {
|
|
32
|
+
throw new Error('apiKey is required (or set DALUX_API_KEY env var)');
|
|
33
|
+
}
|
|
34
|
+
this.baseUrl = resolvedBaseUrl.replace(/\/$/, '');
|
|
35
|
+
this.apiKey = resolvedApiKey;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = Configuration;
|
package/src/index.js
CHANGED
|
@@ -1,92 +1,133 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const Configuration = require('./configuration');
|
|
4
|
-
const ApiClient = require('./apiClient');
|
|
5
|
-
|
|
6
|
-
const CompaniesApi = require('./api/CompaniesApi');
|
|
7
|
-
const CompanyCatalogApi = require('./api/CompanyCatalogApi');
|
|
8
|
-
const FileAreasApi = require('./api/FileAreasApi');
|
|
9
|
-
const FileRevisionsApi = require('./api/FileRevisionsApi');
|
|
10
|
-
const FileUploadApi = require('./api/FileUploadApi');
|
|
11
|
-
const FilesApi = require('./api/FilesApi');
|
|
12
|
-
const FoldersApi = require('./api/FoldersApi');
|
|
13
|
-
const FormsApi = require('./api/FormsApi');
|
|
14
|
-
const InspectionPlansApi = require('./api/InspectionPlansApi');
|
|
15
|
-
const ProjectTemplatesApi = require('./api/ProjectTemplatesApi');
|
|
16
|
-
const ProjectsApi = require('./api/ProjectsApi');
|
|
17
|
-
const TasksApi = require('./api/TasksApi');
|
|
18
|
-
const TestPlansApi = require('./api/TestPlansApi');
|
|
19
|
-
const UsersApi = require('./api/UsersApi');
|
|
20
|
-
const VersionSetsApi = require('./api/VersionSetsApi');
|
|
21
|
-
const WorkPackagesApi = require('./api/WorkPackagesApi');
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Configuration = require('./configuration');
|
|
4
|
+
const ApiClient = require('./apiClient');
|
|
5
|
+
|
|
6
|
+
const CompaniesApi = require('./api/CompaniesApi');
|
|
7
|
+
const CompanyCatalogApi = require('./api/CompanyCatalogApi');
|
|
8
|
+
const FileAreasApi = require('./api/FileAreasApi');
|
|
9
|
+
const FileRevisionsApi = require('./api/FileRevisionsApi');
|
|
10
|
+
const FileUploadApi = require('./api/FileUploadApi');
|
|
11
|
+
const FilesApi = require('./api/FilesApi');
|
|
12
|
+
const FoldersApi = require('./api/FoldersApi');
|
|
13
|
+
const FormsApi = require('./api/FormsApi');
|
|
14
|
+
const InspectionPlansApi = require('./api/InspectionPlansApi');
|
|
15
|
+
const ProjectTemplatesApi = require('./api/ProjectTemplatesApi');
|
|
16
|
+
const ProjectsApi = require('./api/ProjectsApi');
|
|
17
|
+
const TasksApi = require('./api/TasksApi');
|
|
18
|
+
const TestPlansApi = require('./api/TestPlansApi');
|
|
19
|
+
const UsersApi = require('./api/UsersApi');
|
|
20
|
+
const VersionSetsApi = require('./api/VersionSetsApi');
|
|
21
|
+
const WorkPackagesApi = require('./api/WorkPackagesApi');
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
DaluxError,
|
|
25
|
+
NotFoundError,
|
|
26
|
+
ApiError,
|
|
27
|
+
ValidationError,
|
|
28
|
+
AuthenticationError,
|
|
29
|
+
RateLimitError,
|
|
30
|
+
hasNextPage,
|
|
31
|
+
getNextBookmark,
|
|
32
|
+
paginate,
|
|
33
|
+
findByField,
|
|
34
|
+
findAllByField,
|
|
35
|
+
validateProjectId,
|
|
36
|
+
validateFileAreaId,
|
|
37
|
+
validateFolderId,
|
|
38
|
+
resolveFileAreaByName,
|
|
39
|
+
resolveFolderIdFromNamedPath,
|
|
40
|
+
} = require('./utils');
|
|
41
|
+
|
|
42
|
+
const models = require('./models');
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create a fully configured Dalux Build API client.
|
|
46
|
+
*
|
|
47
|
+
* @param {object} [options]
|
|
48
|
+
* @param {string} [options.baseUrl] - The API base URL (falls back to DALUX_BASE_URL env var)
|
|
49
|
+
* @param {string} [options.apiKey] - Your X-API-KEY (falls back to DALUX_API_KEY env var)
|
|
50
|
+
* @returns {{
|
|
51
|
+
* projects: ProjectsApi,
|
|
52
|
+
* companies: CompaniesApi,
|
|
53
|
+
* companyCatalog: CompanyCatalogApi,
|
|
54
|
+
* fileAreas: FileAreasApi,
|
|
55
|
+
* fileRevisions: FileRevisionsApi,
|
|
56
|
+
* fileUpload: FileUploadApi,
|
|
57
|
+
* files: FilesApi,
|
|
58
|
+
* folders: FoldersApi,
|
|
59
|
+
* forms: FormsApi,
|
|
60
|
+
* inspectionPlans: InspectionPlansApi,
|
|
61
|
+
* projectTemplates: ProjectTemplatesApi,
|
|
62
|
+
* tasks: TasksApi,
|
|
63
|
+
* testPlans: TestPlansApi,
|
|
64
|
+
* users: UsersApi,
|
|
65
|
+
* versionSets: VersionSetsApi,
|
|
66
|
+
* workPackages: WorkPackagesApi
|
|
67
|
+
* }}
|
|
68
|
+
*/
|
|
69
|
+
function createClient({ baseUrl, apiKey } = {}) {
|
|
70
|
+
const configuration = new Configuration({ baseUrl, apiKey });
|
|
71
|
+
const apiClient = new ApiClient(configuration);
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
projects: new ProjectsApi(apiClient),
|
|
75
|
+
companies: new CompaniesApi(apiClient),
|
|
76
|
+
companyCatalog: new CompanyCatalogApi(apiClient),
|
|
77
|
+
fileAreas: new FileAreasApi(apiClient),
|
|
78
|
+
fileRevisions: new FileRevisionsApi(apiClient),
|
|
79
|
+
fileUpload: new FileUploadApi(apiClient),
|
|
80
|
+
files: new FilesApi(apiClient),
|
|
81
|
+
folders: new FoldersApi(apiClient),
|
|
82
|
+
forms: new FormsApi(apiClient),
|
|
83
|
+
inspectionPlans: new InspectionPlansApi(apiClient),
|
|
84
|
+
projectTemplates: new ProjectTemplatesApi(apiClient),
|
|
85
|
+
tasks: new TasksApi(apiClient),
|
|
86
|
+
testPlans: new TestPlansApi(apiClient),
|
|
87
|
+
users: new UsersApi(apiClient),
|
|
88
|
+
versionSets: new VersionSetsApi(apiClient),
|
|
89
|
+
workPackages: new WorkPackagesApi(apiClient),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = {
|
|
94
|
+
createClient,
|
|
95
|
+
Configuration,
|
|
96
|
+
ApiClient,
|
|
97
|
+
CompaniesApi,
|
|
98
|
+
CompanyCatalogApi,
|
|
99
|
+
FileAreasApi,
|
|
100
|
+
FileRevisionsApi,
|
|
101
|
+
FileUploadApi,
|
|
102
|
+
FilesApi,
|
|
103
|
+
FoldersApi,
|
|
104
|
+
FormsApi,
|
|
105
|
+
InspectionPlansApi,
|
|
106
|
+
ProjectTemplatesApi,
|
|
107
|
+
ProjectsApi,
|
|
108
|
+
TasksApi,
|
|
109
|
+
TestPlansApi,
|
|
110
|
+
UsersApi,
|
|
111
|
+
VersionSetsApi,
|
|
112
|
+
WorkPackagesApi,
|
|
113
|
+
// Utilities
|
|
114
|
+
DaluxError,
|
|
115
|
+
NotFoundError,
|
|
116
|
+
ApiError,
|
|
117
|
+
ValidationError,
|
|
118
|
+
AuthenticationError,
|
|
119
|
+
RateLimitError,
|
|
120
|
+
hasNextPage,
|
|
121
|
+
getNextBookmark,
|
|
122
|
+
paginate,
|
|
123
|
+
findByField,
|
|
124
|
+
findAllByField,
|
|
125
|
+
validateProjectId,
|
|
126
|
+
validateFileAreaId,
|
|
127
|
+
validateFolderId,
|
|
128
|
+
resolveFileAreaByName,
|
|
129
|
+
resolveFolderIdFromNamedPath,
|
|
130
|
+
// Data models (zod schemas) - both `models.FolderSchema` and top-level `FolderSchema` work
|
|
131
|
+
models,
|
|
132
|
+
...models,
|
|
133
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* API response link. Mirrors python/dalux_build/models/common.py::Link.
|
|
7
|
+
*/
|
|
8
|
+
const LinkSchema = z.object({
|
|
9
|
+
rel: z.string(),
|
|
10
|
+
href: z.string(),
|
|
11
|
+
method: z.string().nullish(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Response metadata with pagination info. Mirrors common.py::Metadata.
|
|
16
|
+
*/
|
|
17
|
+
const MetadataSchema = z.object({
|
|
18
|
+
totalItems: z.number().nullish(),
|
|
19
|
+
totalRemainingItems: z.number().nullish(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
module.exports = { LinkSchema, MetadataSchema };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ProjectCompanySchema } = require('../projects');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/companies/models.py, which re-exports ProjectCompany. */
|
|
7
|
+
const CompaniesListResponseSchema = listResponseSchema(ProjectCompanySchema);
|
|
8
|
+
const CompanyResponseSchema = singleResponseSchema(ProjectCompanySchema);
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
ProjectCompanySchema,
|
|
12
|
+
CompaniesListResponseSchema,
|
|
13
|
+
CompanyResponseSchema,
|
|
14
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Mirrors models/company_catalog/responses.py. These are exported for name
|
|
8
|
+
* parity but, like their Python counterparts, are NOT what the API layer
|
|
9
|
+
* actually uses — company_catalog.py's get_companies/get_company return
|
|
10
|
+
* CompaniesListResponse/CompanyResponse (typed ProjectCompany) instead.
|
|
11
|
+
* See src/api/CompanyCatalogApi.js.
|
|
12
|
+
*/
|
|
13
|
+
const CompanyCatalogListResponseSchema = listResponseSchema(z.any());
|
|
14
|
+
const CompanyCatalogResponseSchema = singleResponseSchema(z.any());
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
CompanyCatalogListResponseSchema,
|
|
18
|
+
CompanyCatalogResponseSchema,
|
|
19
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { ValidationError } = require('../utils/errors');
|
|
5
|
+
const { unwrapData } = require('./helpers');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validate and convert a raw API response into a typed model, throwing a
|
|
9
|
+
* ValidationError if the response doesn't match `schema`. Mirrors
|
|
10
|
+
* response_converter.py::convert_to_model, without its legacy-compat
|
|
11
|
+
* fallback branches (the JS test suite ships schema-valid fixtures).
|
|
12
|
+
* @param {*} response
|
|
13
|
+
* @param {import('zod').ZodTypeAny} schema
|
|
14
|
+
* @param {string} [schemaName]
|
|
15
|
+
* @returns {*}
|
|
16
|
+
*/
|
|
17
|
+
function convertToModel(response, schema, schemaName = 'model') {
|
|
18
|
+
if (response === null || response === undefined) return null;
|
|
19
|
+
try {
|
|
20
|
+
return schema.parse(response);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
if (err instanceof z.ZodError) {
|
|
23
|
+
throw new ValidationError(`Failed to convert response to ${schemaName}: ${err.message}`);
|
|
24
|
+
}
|
|
25
|
+
throw err;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Validate and convert a list of raw items into typed models.
|
|
31
|
+
* Used by get_all_* pagination methods, which convert each item after
|
|
32
|
+
* pagination has already collected the raw list.
|
|
33
|
+
* @param {Array} items
|
|
34
|
+
* @param {import('zod').ZodTypeAny} itemSchema
|
|
35
|
+
* @param {string} [schemaName]
|
|
36
|
+
* @returns {Array}
|
|
37
|
+
*/
|
|
38
|
+
function convertToModelList(items, itemSchema, schemaName = 'model') {
|
|
39
|
+
if (!Array.isArray(items)) return [];
|
|
40
|
+
const wrapped = unwrapData(itemSchema);
|
|
41
|
+
return items.map((item) => convertToModel(item, wrapped, schemaName));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { convertToModel, convertToModelList };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/file_areas/models.py::FileArea (all fields required). */
|
|
7
|
+
const FileAreaSchema = z.object({
|
|
8
|
+
fileAreaId: z.string(),
|
|
9
|
+
fileAreaName: z.string(),
|
|
10
|
+
fileAreaType: z.string(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const FileAreasListResponseSchema = listResponseSchema(FileAreaSchema);
|
|
14
|
+
const FileAreaResponseSchema = singleResponseSchema(FileAreaSchema);
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
FileAreaSchema,
|
|
18
|
+
FileAreasListResponseSchema,
|
|
19
|
+
FileAreaResponseSchema,
|
|
20
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mirrors models/file_revisions/models.py::FileRevision — an empty
|
|
7
|
+
* placeholder in Python too (get_file_revision_content returns raw
|
|
8
|
+
* binary/content in both packages, so there's nothing to validate).
|
|
9
|
+
*/
|
|
10
|
+
const FileRevisionSchema = z.object({}).passthrough();
|
|
11
|
+
|
|
12
|
+
module.exports = { FileRevisionSchema };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mirrors models/file_upload/models.py::FileUpload — empty placeholder in
|
|
7
|
+
* Python too; upload/part/finalize responses are provider-specific and
|
|
8
|
+
* stay raw in both packages.
|
|
9
|
+
*/
|
|
10
|
+
const FileUploadSchema = z.object({}).passthrough();
|
|
11
|
+
|
|
12
|
+
module.exports = { FileUploadSchema };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema, nullableDefault } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/files/models.py::Reference. */
|
|
7
|
+
const ReferenceSchema = z.object({
|
|
8
|
+
key: z.string(),
|
|
9
|
+
value: z.string(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/** Mirrors models/files/models.py::FileIntegerProperty. */
|
|
13
|
+
const FileIntegerPropertySchema = z.object({
|
|
14
|
+
integer: z.number().nullish(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/** Mirrors models/files/models.py::FileDateProperty. */
|
|
18
|
+
const FileDatePropertySchema = z.object({
|
|
19
|
+
date: z.string().nullish(),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/** Mirrors models/files/models.py::FileTextProperty. */
|
|
23
|
+
const FileTextPropertySchema = z.object({
|
|
24
|
+
text: z.string().nullish(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/** Mirrors models/files/models.py::FileReferenceProperty. */
|
|
28
|
+
const FileReferencePropertySchema = z.object({
|
|
29
|
+
reference: ReferenceSchema.nullish(),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** Mirrors models/files/models.py::FilePropertyField. */
|
|
33
|
+
const FilePropertyFieldSchema = z.object({
|
|
34
|
+
key: z.string(),
|
|
35
|
+
name: z.string(),
|
|
36
|
+
values: z.array(z.any()).nullish(),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Mirrors models/files/models.py::FileNameFilter. Client-side filter params
|
|
41
|
+
* (not part of any API response), so field names stay plain camelCase with
|
|
42
|
+
* no aliasing concerns on either side.
|
|
43
|
+
*/
|
|
44
|
+
const FileNameFilterSchema = z.object({
|
|
45
|
+
contains: z.array(z.string()).optional(),
|
|
46
|
+
containsMatch: z.enum(['any', 'all']).default('any'),
|
|
47
|
+
notContains: z.array(z.string()).optional(),
|
|
48
|
+
startswith: z.array(z.string()).optional(),
|
|
49
|
+
notStartswith: z.array(z.string()).optional(),
|
|
50
|
+
endswith: z.array(z.string()).optional(),
|
|
51
|
+
notEndswith: z.array(z.string()).optional(),
|
|
52
|
+
extensions: z.array(z.string()).optional(),
|
|
53
|
+
notExtensions: z.array(z.string()).optional(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Mirrors models/files/models.py::File. `uploaded`/`lastModified` are kept
|
|
58
|
+
* as ISO date strings (not coerced to JS Date) so JSON round-tripping and
|
|
59
|
+
* existing string-based consumer code keeps working.
|
|
60
|
+
*/
|
|
61
|
+
const FileSchema = z.object({
|
|
62
|
+
fileId: z.string(),
|
|
63
|
+
fileRevisionId: z.string().nullish(),
|
|
64
|
+
fileName: z.string(),
|
|
65
|
+
fileAreaId: z.string(),
|
|
66
|
+
folderId: z.string().nullish(),
|
|
67
|
+
uploadedByUserId: z.string().nullish(),
|
|
68
|
+
uploaded: z.string().nullish(),
|
|
69
|
+
lastModifiedByUserId: z.string().nullish(),
|
|
70
|
+
lastModified: z.string().nullish(),
|
|
71
|
+
version: z.string().nullish(),
|
|
72
|
+
deleted: nullableDefault(z.boolean(), false),
|
|
73
|
+
fileType: z.string().nullish(),
|
|
74
|
+
fileSize: z.number().nullish(),
|
|
75
|
+
contentHash: z.string().nullish(),
|
|
76
|
+
downloadLink: z.string().nullish(),
|
|
77
|
+
properties: z.array(FilePropertyFieldSchema).nullish(),
|
|
78
|
+
// Local-only fields set by bulk-download helpers, not present in raw API responses.
|
|
79
|
+
savedFilePath: z.string().nullish(),
|
|
80
|
+
savedMetadataPath: z.string().nullish(),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const FilesListResponseSchema = listResponseSchema(FileSchema);
|
|
84
|
+
const FileResponseSchema = singleResponseSchema(FileSchema);
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
ReferenceSchema,
|
|
88
|
+
FileIntegerPropertySchema,
|
|
89
|
+
FileDatePropertySchema,
|
|
90
|
+
FileTextPropertySchema,
|
|
91
|
+
FileReferencePropertySchema,
|
|
92
|
+
FilePropertyFieldSchema,
|
|
93
|
+
FileNameFilterSchema,
|
|
94
|
+
FileSchema,
|
|
95
|
+
FilesListResponseSchema,
|
|
96
|
+
FileResponseSchema,
|
|
97
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/** Mirrors models/folders/models.py::Folder. */
|
|
7
|
+
const FolderSchema = z.object({
|
|
8
|
+
folderId: z.string(),
|
|
9
|
+
folderName: z.string(),
|
|
10
|
+
parentFolderId: z.string().nullish(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const FoldersListResponseSchema = listResponseSchema(FolderSchema);
|
|
14
|
+
const FolderResponseSchema = singleResponseSchema(FolderSchema);
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
FolderSchema,
|
|
18
|
+
FoldersListResponseSchema,
|
|
19
|
+
FolderResponseSchema,
|
|
20
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { listResponseSchema, singleResponseSchema } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Mirrors models/forms/models.py::Form — empty placeholder in Python, so
|
|
8
|
+
* items stay untyped.
|
|
9
|
+
*/
|
|
10
|
+
const FormSchema = z.any();
|
|
11
|
+
|
|
12
|
+
const FormsListResponseSchema = listResponseSchema(FormSchema);
|
|
13
|
+
const FormResponseSchema = singleResponseSchema(FormSchema);
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
FormSchema,
|
|
17
|
+
FormsListResponseSchema,
|
|
18
|
+
FormResponseSchema,
|
|
19
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { z } = require('zod');
|
|
4
|
+
const { LinkSchema, MetadataSchema } = require('./common');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Unwraps a `{ data: {...} }` wrapper before validating against `schema`.
|
|
8
|
+
* Bare objects (no `data` wrapper) pass straight through.
|
|
9
|
+
* Mirrors the `unwrap_and_convert_items` field_validator repeated across
|
|
10
|
+
* every Python `responses.py` file.
|
|
11
|
+
* @param {import('zod').ZodTypeAny} schema
|
|
12
|
+
*/
|
|
13
|
+
function unwrapData(schema) {
|
|
14
|
+
return z.preprocess((value) => {
|
|
15
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && 'data' in value) {
|
|
16
|
+
return value.data;
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}, schema);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Builds a `{ items, metadata?, links? }` list-response schema.
|
|
24
|
+
* Accepts a bare array payload too (wraps it as `{ items: [...] }`) —
|
|
25
|
+
* mirrors TaskChanges' `wrap_list_payloads` model_validator.
|
|
26
|
+
* @param {import('zod').ZodTypeAny} itemSchema
|
|
27
|
+
*/
|
|
28
|
+
function listResponseSchema(itemSchema) {
|
|
29
|
+
return z.preprocess(
|
|
30
|
+
(value) => (Array.isArray(value) ? { items: value } : value),
|
|
31
|
+
z.object({
|
|
32
|
+
items: z.array(unwrapData(itemSchema)).default([]),
|
|
33
|
+
metadata: MetadataSchema.optional(),
|
|
34
|
+
links: z.array(LinkSchema).optional(),
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Builds a `{ data, links? }` single-item response schema.
|
|
41
|
+
* @param {import('zod').ZodTypeAny} itemSchema
|
|
42
|
+
*/
|
|
43
|
+
function singleResponseSchema(itemSchema) {
|
|
44
|
+
return z.object({
|
|
45
|
+
data: itemSchema,
|
|
46
|
+
links: z.array(LinkSchema).optional(),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A defaulted field that also accepts an explicit JSON `null` (treated the
|
|
52
|
+
* same as an absent field) — mirrors Pydantic's `Optional[T] = default`,
|
|
53
|
+
* which accepts both a missing key and an explicit `null`. Plain
|
|
54
|
+
* `schema.default(x)` alone only fires on `undefined`, not `null`.
|
|
55
|
+
* @param {import('zod').ZodTypeAny} schema
|
|
56
|
+
* @param {*} defaultValue
|
|
57
|
+
*/
|
|
58
|
+
function nullableDefault(schema, defaultValue) {
|
|
59
|
+
return z.preprocess((v) => (v === null ? undefined : v), schema.default(defaultValue));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { unwrapData, listResponseSchema, singleResponseSchema, nullableDefault };
|