@camunda8/sdk
Version:
[](https://www.npmjs.com/package/@camunda8/sdk)
491 lines • 19.3 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModelerApiClient = void 0;
const debug_1 = __importDefault(require("debug"));
const got_1 = __importDefault(require("got"));
const lib_1 = require("../../lib");
const debug = (0, debug_1.default)('camunda:modeler');
const API_VERSION = 'v1';
/**
* Modeler REST API Client.
* All constructor parameters for configuration are optional. If no configuration is provided, the SDK will use environment variables to configure itself.
* See {@link CamundaSDKConfiguration} for the complete list of configuration parameters. Values can be passed in explicitly in code, or set via environment variables (recommended: separate configuration and application logic).
* Explicitly set values will override environment variables, which are merged into the configuration.
*/
class ModelerApiClient {
constructor(options) {
const config = lib_1.CamundaEnvironmentConfigurator.mergeConfigWithEnvironment(options?.config ?? {});
const modelerApiUrl = config.CAMUNDA_MODELER_BASE_URL;
this.oAuthProvider =
options?.oAuthProvider ??
(0, lib_1.constructOAuthProvider)(config, {
explicitFromConstructor: Object.prototype.hasOwnProperty.call(options?.config ?? {}, 'CAMUNDA_AUTH_STRATEGY'),
});
this.userAgentString = (0, lib_1.createUserAgentString)(config);
const prefixUrl = `${modelerApiUrl}/${API_VERSION}`;
this.rest = (0, lib_1.GetCustomCertificateBuffer)(config).then((certificateAuthority) => got_1.default.extend({
prefixUrl,
retry: lib_1.GotRetryConfig,
https: {
certificateAuthority,
},
handlers: [lib_1.beforeCallHook],
hooks: {
beforeError: [(0, lib_1.gotBeforeErrorHook)(config)],
beforeRequest: config.middleware ?? [],
},
}));
debug(`baseUrl: ${prefixUrl}`);
}
async getHeaders() {
const authorization = await this.oAuthProvider.getHeaders('MODELER');
const headers = {
'content-type': 'application/json',
...authorization,
'user-agent': this.userAgentString,
accept: '*/*',
};
return headers;
}
decodeResponseOrThrow(res) {
if (res.statusCode === 200) {
return res.body;
}
// 204: No Content
if (res.statusCode === 204) {
return '{}';
}
const err = new Error(res.statusMessage);
err.code = res.statusCode;
throw err;
}
/**
* Adds a new collaborator to a project or modifies the permission level of an existing collaborator.
* Note: Only users that are part of the authorized organization (see GET /api/v1/info) and logged in to Web Modeler at least once can be added to a project.
* @throws {RESTError}
*/
async addCollaborator(req) {
const headers = await this.getHeaders();
return got_1.default
.put(`collaborators`, {
headers,
body: JSON.stringify(req),
})
.then(this.decodeResponseOrThrow);
}
/**
* Searches for collaborators.
* filter specifies which fields should match. Only items that match the given fields will be returned.
* sort specifies by which fields and direction (ASC/DESC) the result should be sorted.
* page specifies the page number to return.
* size specifies the number of items per page. The default value is 10.
* @throws {RESTError}
*/
async searchCollaborators(req) {
const headers = await this.getHeaders();
return got_1.default
.post(`collaborators/search`, {
headers,
body: JSON.stringify(req),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* @throws {RESTError}
* @returns
*/
async deleteCollaborator({ email, projectId, }) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.delete(`project/${projectId}collaborators/${email}`, {
headers,
})
.then(this.decodeResponseOrThrow);
}
/**
* This endpoint creates a file.
*
* To create a file, specify projectId and/or folderId:
*
* When only folderId is given, the file will be created in that folder. The folder can be in any project of the same organization.
*
* When projectId is given and folderId is either null or omitted altogether, the file will be created in the root of the project.
*
* When projectId and folderId are both given, they must be consistent - i.e. the folder is in the project.
*
* For connector templates, the following constraints apply:
*
* The value of content.$schema will be replaced with https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json and validated against it.
*
* The value of name takes precedence over content.name. In case of mismatch, the latter will be adjusted to match the former automatically.
*
* The value of content.id will be replaced with the file id generated by Web Modeler.
*
* The value of content.version is managed by Web Modeler and will be updated automatically.
*
* Note: The simplePath transforms any occurrences of slashes ("/") in file and folder names into an escape sequence consisting of a backslash followed by a slash ("\/").
* This form of escaping facilitates the processing of path-like structures within file and folder names.
* @throws {RESTError}
*/
async createFile(req) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.post(`files`, {
headers,
body: JSON.stringify(req),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
* Retrieves a file.
*
* Note: The simplePath transforms any occurrences of slashes ("/") in file and folder names into an
* escape sequence consisting of a backslash followed by a slash ("\/"). This form of escaping
* facilitates the processing of path-like structures within file and folder names.
*
* Does this throw if it is not found?
* @throws {RESTError}
*/
async getFile(fileId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest(`files/${fileId}`, {
headers,
}).then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
* Deletes a file.
* Note: Deleting a file will also delete other resources attached to the file (comments, call activity/business rule task links, milestones and shares) which might have side-effects.
* Deletion of resources is recursive and cannot be undone.
* @throws {RESTError}
*/
async deleteFile(fileId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.delete(`files/${fileId}`, {
headers,
})
.then(this.decodeResponseOrThrow);
}
/**
* Updates the content, name, or location of a file, or all at the same time.
*
* To move a file, specify projectId and/or folderId:
* When only folderId is given, the file will be moved to that folder. The folder can be in another project of the same organization.
* When projectId is given and folderId is either null or omitted altogether, the file will be moved to the root of the project.
* When projectId and folderId are both given, they must be consistent - i.e. the new parent folder is in the new project.
* The field revision holds the current revision of the file. This is used for detecting and preventing concurrent modifications.
* For connector templates, the following constraints apply:
* The value of content.$schema is not updatable.
* The value of content.name can only be changed via name.
* The value of content.id is not updatable.
* The value of content.version is managed by Web Modeler and will be updated automatically.
* Note: The simplePath transforms any occurrences of slashes ("/") in file and folder names into an escape sequence consisting of a backslash followed by a slash ("\/").
* This form of escaping facilitates the processing of path-like structures within file and folder names.
* @throws {RESTError}
*/
async updateFile(fileId, update) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.patch(`files/${fileId}`, {
headers,
body: JSON.stringify(update),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
* Searches for files.
* filter specifies which fields should match. Only items that match the given fields will be returned.
*
* Note: Date fields need to be specified in a format compatible with java.time.ZonedDateTime; for example 2023-09-20T11:31:20.206801604Z.
*
* You can use suffixes to match date ranges:
*
* Modifier Description
* ||/y Within a year
* ||/M Within a month
* ||/w Within a week
* ||/d Within a day
* ||/h Within an hour
* ||/m Within a minute
* ||/s Within a second
*
* sort specifies by which fields and direction (ASC/DESC) the result should be sorted.
*
* page specifies the page number to return.
* size specifies the number of items per page. The default value is 10.
*
* Note: The simplePath transform any occurrences of slashes ("/") in file and folder names into an escape sequence consisting of a backslash followed by a slash ("\/").
* This form of escaping facilitates the processing of path-like structures within file and folder names.
* @throws {RESTError}
*/
async searchFiles(req) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.post(`files/search`, {
headers,
body: JSON.stringify(req),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* Creates a new folder.
*
* When only parentId is given, the folder will be created in that folder. The folder can be in any project of the same organization.
*
* When projectId is given and parentId is either null or omitted altogether, the folder will be created in the root of the project.
*
* When projectId and parentId are both given, they must be consistent - i.e. the parent folder is in the project.
* @throws {RESTError}
*/
async createFolder(req) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.post(`folders`, {
headers,
body: JSON.stringify(req),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* @throws {RESTError}
* @returns
*/
async getFolder(folderId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest(`folders/${folderId}`, {
headers,
}).then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* Deletes an empty folder. A folder is considered empty if there are no files in it. Deletion of resources is recursive and cannot be undone.
* @throws {RESTError}
*/
async deleteFolder(folderId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.delete(`folders/${folderId}`, {
headers,
})
.then(this.decodeResponseOrThrow);
}
/**
* Updates the name or location of a folder, or both at the same time.
*
* To move a folder, specify projectId and/or parentId:
*
* When only parentId is given, the file will be moved to that folder. The folder must keep in the same organization.
*
* When projectId is given and parentId is either null or omitted altogether, the file will be moved to the root of the project.
*
* When projectId and parentId are both given, they must be consistent - i.e. the new parent folder is in the new project.
* @throws {RESTError}
*/
async updateFolder(folderId, update) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.patch(`folders/${folderId}`, {
headers,
body: JSON.stringify(update),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* @throws {RESTError}
*/
async getInfo() {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest(`info`, {
headers,
}).then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* @throws {RESTError}
*/
async createMilestone(req) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.post(`milestones`, {
headers,
body: JSON.stringify(req),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* @throws {RESTError}
*/
async getMilestone(milestoneId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest(`milestones/${milestoneId}`, {
headers,
}).then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
* Deletion of resources is recursive and cannot be undone.
* @throws {RESTError}
*/
async deleteMilestone(milestoneId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest(`milestones/${milestoneId}`, {
headers,
}).then(this.decodeResponseOrThrow);
}
/**
* Returns a link to a visual comparison between two milestones where the milestone referenced by milestone1Id acts as a baseline to compare the milestone referenced by milestone2Id against.
* @throws {RESTError}
*/
async getMilestoneComparison(milestone1Id, milestone2Id) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest(`milestones/compare/${milestone1Id}...${milestone2Id}`, {
headers,
}).then(this.decodeResponseOrThrow);
}
/**
* Searches for milestones.
*
* filter specifies which fields should match. Only items that match the given fields will be returned.
*
* Note: Date fields need to be specified in a format compatible with java.time.ZonedDateTime; for example 2023-09-20T11:31:20.206801604Z.
*
* You can use suffixes to match date ranges:
*
* Modifier Description
* ||/y Within a year
* ||/M Within a month
* ||/w Within a week
* ||/d Within a day
* ||/h Within an hour
* ||/m Within a minute
* ||/s Within a second
* sort specifies by which fields and direction (ASC/DESC) the result should be sorted.
*
* page specifies the page number to return.
*
* size specifies the number of items per page. The default value is 10.
* @throws {RESTError}
*/
async searchMilestones(req) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.post(`milestones/search`, {
headers,
body: JSON.stringify(req),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
* Creates a new project. This project will be created without any collaborators, so it will not be visible in the UI by default. To assign collaborators, use `addCollaborator()`.
* @throws {RESTError}
*/
async createProject(name) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.post(`projects`, {
headers,
body: JSON.stringify({ name }),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* @throws {RESTError}
* @returns
*/
async getProject(projectId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest(`projects/${projectId}`, {
headers,
}).then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
* This endpoint deletes an empty project. A project is considered empty if there are no files in it. Deletion of resources is recursive and cannot be undone.
* @throws {RESTError}
*/
async deleteProject(projectId) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.delete(`projects/${projectId}`, {
headers,
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
*
* @throws {RESTError}
*/
async renameProject(projectId, name) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.patch(`projects/${projectId}`, {
headers,
body: JSON.stringify({ name }),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
/**
* Searches for projects.
*
* filter specifies which fields should match. Only items that match the given fields will be returned.
*
* Note: Date fields need to be specified in a format compatible with java.time.ZonedDateTime; for example 2023-09-20T11:31:20.206801604Z.
*
* You can use suffixes to match date ranges:
*
* Modifier Description
* ||/y Within a year
* ||/M Within a month
* ||/w Within a week
* ||/d Within a day
* ||/h Within an hour
* ||/m Within a minute
* ||/s Within a second
*
* sort specifies by which fields and direction (ASC/DESC) the result should be sorted.
*
* page specifies the page number to return.
*
* size specifies the number of items per page. The default value is 10.
* @throws {RESTError}
*/
async searchProjects(req) {
const headers = await this.getHeaders();
const rest = await this.rest;
return rest
.post(`projects/search`, {
headers,
body: JSON.stringify(req),
})
.then((res) => JSON.parse(this.decodeResponseOrThrow(res)));
}
}
exports.ModelerApiClient = ModelerApiClient;
//# sourceMappingURL=ModelerAPIClient.js.map