youtrack-client
Version:
Client library for accessing the YouTrack REST and Widget API
1 lines • 311 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/utils/common.ts","../src/utils/fetchHelpers.ts","../src/utils/queryBuilder.ts","../src/resources/common.ts","../src/resources/Activities.ts","../src/resources/Agiles.ts","../src/resources/Articles.ts","../src/resources/Commands.ts","../src/resources/Groups.ts","../src/resources/IssueLinkTypes.ts","../src/resources/Issues.ts","../src/resources/SavedQueries.ts","../src/resources/Search.ts","../src/resources/Tags.ts","../src/resources/Users.ts","../src/resources/WorkItems.ts","../src/resources/IssueComments.ts","../src/resources/IssueLinks.ts","../src/resources/IssueTags.ts","../src/resources/IssueTimeTracking.ts","../src/resources/IssueVcsChanges.ts","../src/resources/IssueAttachments.ts","../src/resources/admin/Projects.ts","../src/resources/admin/BuildBundles.ts","../src/resources/admin/EnumBundles.ts","../src/resources/admin/OwnedBundles.ts","../src/resources/admin/StateBundles.ts","../src/resources/admin/UserBundles.ts","../src/resources/admin/VersionBundles.ts","../src/resources/admin/Workflows.ts","../src/resources/admin/CustomFields.ts","../src/resources/admin/BackupFiles.ts","../src/resources/admin/GlobalSettings.ts","../src/resources/admin/TelemetryData.ts","../src/resources/admin/DatabaseBackupSettings.ts","../src/resources/admin/GlobalTimeTrackingSettings.ts","../src/youtrack.ts"],"sourcesContent":["export const isObject = (value: unknown): value is Record<string | number | symbol, unknown> => {\n return value !== null && typeof value === \"object\"\n}\n\nexport const joinUrl = (_baseUrl: string, _url: string): string => {\n let baseUrl = _baseUrl\n let url = _url\n // Ensure baseUrl does not end with a '/'\n if (baseUrl.endsWith(\"/\")) {\n baseUrl = baseUrl.slice(0, -1)\n }\n\n // Ensure url does not start with a '/'\n if (url.startsWith(\"/\")) {\n url = url.slice(1)\n }\n\n return `${baseUrl}/${url}`\n}\n","import type { FieldsSchema, QueryParamBuilder, Schema } from \"../types\"\nimport { isObject } from \"./common\"\n\nexport const encodeBody = (data?: string | object | FormData): string | FormData | undefined => {\n if (data instanceof FormData) {\n return data\n }\n\n if (typeof data === \"object\") {\n return JSON.stringify(data)\n }\n\n return data\n}\n\n// Function to build the URI with path parameters\nexport const buildUri = (baseUri: string, pathParams: Record<string, string> = {}): string =>\n Object.keys(pathParams).reduce(\n (uri, param) => uri.replace(`:${param}`, encodeURIComponent(pathParams[param])),\n baseUri,\n ) // Replace path parameters in the URI\n\nexport const createParamsMap = (keys: string[] = [], values: Array<string | number> = []) => {\n return keys.reduce(\n (res, key, index) => {\n res[key] = `${values[index]}`\n return res\n },\n {} as Record<string, string>,\n )\n}\n\nconst fieldsBuilder = (schema: FieldsSchema = []): string => {\n const _fields = schema.map((field) =>\n isObject(field)\n ? Object.keys(field)\n .map((key) => `${key}(${fieldsBuilder(field[key])})`)\n .join(\",\")\n : encodeURIComponent(field),\n )\n return _fields.length ? _fields.join(\",\") : \"\"\n}\n\nexport const fields: QueryParamBuilder<Schema<any> | undefined> = (schema = []) => {\n const _fields = typeof schema === \"string\" ? schema : fieldsBuilder(schema)\n return _fields ? `fields=${_fields}` : \"\"\n}\n\nexport const buildQueryParam = (key: string, value?: string | number | boolean | string[] | number[] | boolean[]) => {\n if (Array.isArray(value)) {\n return value.map((item) => `${encodeURIComponent(key)}=${encodeURIComponent(item)}`)\n }\n return typeof value !== \"undefined\" ? `${encodeURIComponent(key)}=${encodeURIComponent(value)}` : \"\"\n}\n\nexport const stringParam =\n (key: string): QueryParamBuilder<string | undefined> =>\n (value?) =>\n buildQueryParam(key, value)\n\nexport const queryParams = <TKey extends string, T extends string | number | boolean | string[] | number[] | boolean[]>(\n ...keys: TKey[]\n): Record<TKey, QueryParamBuilder<T | undefined>> => {\n return keys.reduce(\n (params, key) => {\n params[key] = (value?) => buildQueryParam(key, value)\n return params\n },\n {} as Record<TKey, QueryParamBuilder<T | undefined>>,\n )\n}\n\nexport const customField: QueryParamBuilder<string | string[] | undefined> = (value) =>\n buildQueryParam(\"customField\", value)\n","import type { FetchConfig, QueryParamBuilder } from \"../types\"\nimport { buildQueryParam } from \"./fetchHelpers\"\n\nexport type Builders<T extends Record<string, any>> = {\n [K in keyof T]-?: QueryParamBuilder<T[K]> | \"string\" | \"number\" | \"boolean\"\n}\n\nexport class RequestBuilder<T extends Record<string, any>> {\n private _args: string[] = []\n\n constructor(\n private baseUrl: string,\n builders: Builders<T>,\n params: T = {} as T,\n ) {\n Object.keys(params).forEach((key) => {\n // Dynamically create setters for each key\n if (key in builders) {\n const value = builders[key]\n const arg = typeof value !== \"function\" ? buildQueryParam(key, params[key]) : value(params[key])\n if (arg) {\n this._args.push(...(Array.isArray(arg) ? arg : [arg]))\n }\n }\n })\n }\n\n // Method to build the query string\n private build(options?: Omit<FetchConfig, \"url\">): FetchConfig {\n const query = this._args.join(\"&\")\n return {\n ...options,\n url: query ? `${this.baseUrl}?${query}` : this.baseUrl,\n }\n }\n\n public get() {\n return this.build()\n }\n\n public post<TBody extends object>(data: TBody) {\n return this.build({ method: \"POST\", data })\n }\n\n public postFile(data: FormData) {\n return this.build({ method: \"POST\", data, headers: { \"Content-Type\": \"multipart/form-data\" } })\n }\n\n public delete() {\n return this.build({ method: \"DELETE\" })\n }\n\n public put() {\n return this.build({ method: \"PUT\" })\n }\n\n public patch() {\n return this.build({ method: \"PATCH\" })\n }\n}\n","import type { YouTrack } from \"../youtrack\"\n\nexport class ResourceApi {\n constructor(protected youtrack: YouTrack) {}\n}\n","import type {\n ActivityCategory,\n ActivityCursorPage,\n ActivityItem,\n Entity,\n FieldsParam,\n ListParams,\n Schema,\n} from \"../types\"\nimport { fields, queryParams, RequestBuilder } from \"../utils\"\nimport { ResourceApi } from \"./common\"\n\ntype ActivityItemSchema = Schema<ActivityItem>\ntype ActivityCursorPageSchema = Schema<ActivityCursorPage>\n\ntype ActivityItemEntity<TSchema extends ActivityItemSchema> = Entity<ActivityItem, TSchema>\ntype ActivityCursorPageEntity<TSchema extends ActivityCursorPageSchema> = Entity<ActivityCursorPage, TSchema>\n\ntype GetActivitiesParams = {\n categories?: ActivityCategory[]\n reverse?: boolean\n start?: string\n end?: string\n author?: string\n issueQuery?: string\n}\n\ntype GetActivitiesPageParams = GetActivitiesParams & {\n cursor?: string\n activityId?: string\n}\n\n/**\n * This resource provides access to the activities with the possibility to filter them by various parameters.\n * https://www.jetbrains.com/help/youtrack/devportal/resource-api-activities.html\n */\nexport class ActivitiesApi extends ResourceApi {\n /**\n * Get the list of all available activities.\n * @param params - Optional parameters for the request.\n * @param params.fields - A list of ActivityItem attributes to include in the response. If not specified, only the entityID is returned.\n * @param params.$skip - The number of entries to skip in the response. Useful for pagination.\n * @param params.$top - The maximum number of entries to return. If not specified, the server limits the number of entries returned.\n * @param params.categories - Mandatory. Filters returned activities by categories. Can be specified as a single category or a comma-separated list of categories. At least one category must be specified.\n * @param params.reverse - Indicates whether the order of returned activities is from newest to oldest (true) or oldest to newest (false). Default is false.\n * @param params.start - Timestamp in milliseconds indicating the start of the time interval. If not set, defaults to 0.\n * @param params.end - Timestamp in milliseconds indicating the end of the time interval. If not set, defaults to Long.MAX_VALUE.\n * @param params.author - Filters activities by author. Can be specified as the database ID, login, Hub ID, or \"me\" for the currently logged in user.\n * @param params.issueQuery - Issue search query to filter activities related to specific issues.\n * @returns A list of activities matching the specified criteria.\n */\n async getActivities<TSchema extends ActivityItemSchema>(\n params?: ListParams & FieldsParam<TSchema> & GetActivitiesParams,\n ): Promise<ActivityItemEntity<TSchema>[]> {\n return this.youtrack.fetch<ActivityItemEntity<TSchema>[]>(\n new RequestBuilder(\n \"api/activities\",\n {\n fields,\n ...queryParams(\"$skip\", \"$top\", \"reverse\", \"categories\", \"author\", \"start\", \"end\", \"issueQuery\"),\n },\n params,\n ).get(),\n )\n }\n\n /**\n * Get information about a specific activity item.\n * @param itemId - The ID of the activity item to retrieve.\n * @param params - Optional parameters for the request.\n * @param params.fields - A list of ActivityItem attributes to include in the response. If not specified, only the entityID is returned.\n * @returns The details of the specified activity item.\n */\n async getActivityById<TSchema extends ActivityItemSchema>(\n itemId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ActivityItemEntity<TSchema>> {\n return this.youtrack.fetch<ActivityItemEntity<TSchema>>(\n new RequestBuilder(`api/activities/${itemId}`, { fields }, params).get(),\n )\n }\n\n /**\n * Read a page of activities.\n * @param params - Parameters for the request.\n * @param params.fields - A comma-separated list of ActivityCursorPage attributes to include in the response. If not specified, only the entityID is returned.\n * @param params.categories - Mandatory. Filters returned activities by one or more categories. At least one category must be specified.\n * @param params.reverse - Indicates whether the order of returned activities is from newest to oldest (true) or oldest to newest (false). Default is false.\n * @param params.start - Timestamp in milliseconds indicating the start of the time interval. Defaults to 0 if not provided.\n * @param params.end - Timestamp in milliseconds indicating the end of the time interval. Defaults to Long.MAX_VALUE if not provided.\n * @param params.author - Filters activities by author. Can be specified as the database ID, login, Hub ID, or \"me\" for the currently logged in user.\n * @param params.issueQuery - Filters activities related to specific issues using a search query.\n * @param params.cursor - Used for pagination. Indicates the position in the activity collection to start the next page. Cursors should be taken from previous responses.\n * @param params.activityId - ID of an activity to be included in the middle of the page. Helps to start the page from a specific activity.\n * @returns A page of activities with pagination support, including cursors for navigation.\n */\n async getActivitiesPage<TSchema extends ActivityCursorPageSchema>(\n params?: GetActivitiesPageParams & FieldsParam<TSchema>,\n ): Promise<ActivityCursorPageEntity<TSchema>> {\n // Perform the fetch request\n return this.youtrack.fetch<ActivityCursorPageEntity<TSchema>>(\n new RequestBuilder(\n \"api/activitiesPage\",\n {\n fields,\n ...queryParams(\"categories\", \"reverse\", \"author\", \"start\", \"end\", \"issueQuery\", \"cursor\", \"activityId\"),\n },\n params,\n ).get(),\n )\n }\n}\n","import type { Agile, Sprint, Entity, FieldsParam, ListParams, Schema, DeepPartial } from \"../types\"\nimport { RequestBuilder, fields } from \"../utils\"\nimport { ResourceApi } from \"./common\"\n\ntype AgileSchema = Schema<Agile> | undefined\ntype SprintSchema = Schema<Sprint> | undefined\n\ntype AgileEntity<TSchema extends AgileSchema> = Entity<Agile, TSchema>\ntype SprintEntity<TSchema extends SprintSchema> = Entity<Sprint, TSchema>\n\nexport type AgileTemplateParam = {\n template?: \"kanban\" | \"scrum\" | \"version\" | \"custom\" | \"personal\"\n}\n\n/**\n * This resource lets you work with agile boards in YouTrack.\n * https://www.jetbrains.com/help/youtrack/devportal/resource-api-agiles.html\n */\nexport class AgilesApi extends ResourceApi {\n /**\n * Get the list of all available agile boards in the system.\n * @param params - Optional parameters for the request.\n * @param params.fields - A list of Agile attributes that should be returned in the response. If no field is specified, only the entityID is returned.\n * @param params.$skip - Optional. Lets you set a number of returned entities to skip before returning the first one.\n * @param params.$top - Optional. Lets you specify the maximum number of entries that are returned in the response. If you don't set the $top value, the server limits the maximum number of returned entries.\n * @returns The list of all available agile boards\n */\n async getAgiles<TSchema extends AgileSchema = undefined>(\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<AgileEntity<TSchema>[]> {\n return this.youtrack.fetch<AgileEntity<TSchema>[]>(\n new RequestBuilder(\"api/agiles\", { fields, $skip: \"number\", $top: \"number\" }, params).get(),\n )\n }\n\n /**\n * Create a new agile board\n * @param body - Body with required fields: name, projects (id - Ids of the project that need to be associated with the board).\n * @param params - Optional parameters for the request.\n * @param params.fields - A list of Agile attributes that should be returned in the response. If no field is specified, only the entityID is returned.\n * @param params.template - The name of the board template that should be used. Possible values: kanban, scrum, version, custom, personal.\n * @returns The created agile board.\n */\n async createAgile<TSchema extends AgileSchema>(\n body: Omit<Agile, \"id\">,\n params?: AgileTemplateParam & FieldsParam<TSchema>,\n ): Promise<AgileEntity<TSchema>[]> {\n return this.youtrack.fetch<AgileEntity<TSchema>[]>(\n new RequestBuilder(\"api/agiles\", { fields, template: \"string\" }, params).post(body),\n )\n }\n\n /**\n * Get settings of the specific agile board.\n * @param agileId - The ID of the agile board.\n * @param params - Optional parameters for the request.\n * @param params.fields - A list of Agile attributes to include in the response. If not specified, only the entityId is returned.\n * @returns The settings of the specified agile board.\n */\n async getAgileById<TSchema extends AgileSchema>(\n agileId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<AgileEntity<TSchema>> {\n return this.youtrack.fetch<AgileEntity<TSchema>>(\n new RequestBuilder(`api/agiles/${agileId}`, { fields }, params).get(),\n )\n }\n\n /**\n * Update settings of the specific agile board.\n * @param agileId - The Id of the agile board.\n * @param body - The updated settings for the agile board, excluding the Id.\n * @param params - Optional parameters for the request.\n * @param params.fields - A list of Agile attributes to include in the response. If not specified, only the entityId is returned.\n * @returns The updated settings of the specified agile board.\n */\n async updateAgile<TSchema extends AgileSchema>(\n agileId: string,\n body: DeepPartial<Agile>,\n params?: FieldsParam<TSchema>,\n ): Promise<AgileEntity<TSchema>> {\n return this.youtrack.fetch<AgileEntity<TSchema>>(\n new RequestBuilder(`api/agiles/${agileId}`, { fields }, params).post(body),\n )\n }\n\n /**\n * Delete an agile board with the specific Id.\n * @param agileId - The Id of the agile board.\n * @param params - Optional parameters including fields.\n * @param params.fields - A list of Agile attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The deleted agile board information.\n */\n async deleteAgile<TSchema extends AgileSchema>(\n agileId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<AgileEntity<TSchema>> {\n return this.youtrack.fetch<AgileEntity<TSchema>>(\n new RequestBuilder(`api/agiles/${agileId}`, { fields }, params).delete(),\n )\n }\n /**\n * Get the list of all sprints of the agile board.\n * @param agileID - The ID of the agile board.\n * @param params - Optional parameters including fields, $skip, and $top for pagination.\n * @param params.fields - A list of Agile attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.$skip - The number of entries to skip in the response. Useful for pagination.\n * @param params.$top - The maximum number of entries to return. If not specified, the server limits the number of entries returned.\n * @returns The list of sprints for the specified agile board.\n */\n async getAgileSprints<TSchema extends SprintSchema>(\n agileId: string,\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<SprintEntity<TSchema>[]> {\n return this.youtrack.fetch<SprintEntity<TSchema>[]>(\n new RequestBuilder(`api/agiles/${agileId}/sprints`, { fields, $skip: \"number\", $top: \"number\" }, params).get(),\n )\n }\n\n /**\n * Create a new sprint for the specified agile board.\n * @param agileID - The ID of the agile board.\n * @param body - The new sprint details including the required field: name.\n * @param params - Optional parameters for the request.\n * @param params.fields - Optional. A list of Sprint attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.muteUpdateNotifications - Optional. Set this parameter to true if no notifications should be sent on changes made by this request.\n * @returns The created sprint.\n */\n async createAgileSprint<TSchema extends SprintSchema>(\n agileId: string,\n body: { name: string } | DeepPartial<Sprint>, // Required field: name\n params?: FieldsParam<TSchema> & { muteUpdateNotifications?: boolean },\n ): Promise<SprintEntity<TSchema>> {\n return this.youtrack.fetch<SprintEntity<TSchema>>(\n new RequestBuilder(`api/agiles/${agileId}/sprints`, { fields, muteUpdateNotifications: \"boolean\" }, params).post(\n body,\n ),\n )\n }\n\n /**\n * Get settings of the specific sprint of the agile board.\n * @param agileId - The Id of the agile board.\n * @param sprintId - The Id of the sprint or \"current\" for the current sprint.\n * @param params - Optional parameters for the request.\n * @param params.fields - Optional. A list of Sprint attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The settings of the specified sprint.\n */\n async getAgileSprintById<TSchema extends SprintSchema>(\n agileId: string,\n sprintId: string | \"current\",\n params?: FieldsParam<TSchema>,\n ): Promise<SprintEntity<TSchema>> {\n return this.youtrack.fetch<SprintEntity<TSchema>>(\n new RequestBuilder(`api/agiles/${agileId}/sprints/${sprintId}`, { fields }, params).get(),\n )\n }\n\n /**\n * Delete the specific sprint from the agile board.\n * @param agileId - The Id of the agile board.\n * @param sprintId - The Id of the sprint to be deleted.\n * @param params - Optional parameters for the request.\n * @param params.fields - Optional. A list of Sprint attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The deleted sprint information.\n */\n async deleteAgileSprint<TSchema extends SprintSchema>(\n agileId: string,\n sprintId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<SprintEntity<TSchema>> {\n return this.youtrack.fetch<SprintEntity<TSchema>>(\n new RequestBuilder(`api/agiles/${agileId}/sprints/${sprintId}`, { fields }, params).delete(),\n )\n }\n\n /**\n * Update the specific sprint of the agile board.\n * @param agileId - The Id of the agile board.\n * @param sprintId - The Id of the sprint or \"current\" for the current sprint.\n * @param body - The updated sprint details excluding the Id.\n * @param params - Optional parameters for the request.\n * @param params.fields - A list of Sprint attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The updated sprint information.\n */\n async updateAgileSprint<TSchema extends SprintSchema>(\n agileId: string,\n sprintId: string | \"current\",\n body: DeepPartial<Sprint>, // Body contains the updated sprint settings\n params?: FieldsParam<TSchema>,\n ): Promise<SprintEntity<TSchema>> {\n return this.youtrack.fetch<SprintEntity<TSchema>>(\n new RequestBuilder(`api/agiles/${agileId}/sprints/${sprintId}`, { fields }, params).post(body),\n )\n }\n}\n","import type {\n Article,\n ArticleAttachment,\n ArticleComment,\n DeepPartial,\n Entity,\n FieldsParam,\n ListParams,\n MuteUpdateNotificationsParam,\n Reaction,\n Schema,\n Tag,\n} from \"../types\"\nimport { fields, queryParams, RequestBuilder } from \"../utils\"\nimport { ResourceApi } from \"./common\"\n\ntype ArticleSchema = Schema<Article>\ntype ArticleCommentSchema = Schema<ArticleComment>\ntype ArticleAttachmentSchema = Schema<ArticleAttachment>\ntype ReactionSchema = Schema<Reaction>\ntype TagSchema = Schema<Tag>\n\ntype ArticleEntity<TSchema extends ArticleSchema> = Entity<Article, TSchema>\ntype ArticleCommentEntity<TSchema extends ArticleCommentSchema> = Entity<ArticleComment, TSchema>\ntype ArticleAttachmentEntity<TSchema extends ArticleAttachmentSchema> = Entity<ArticleAttachment, TSchema>\ntype ReactionEntity<TSchema extends ReactionSchema> = Entity<Reaction, TSchema>\ntype TagEntity<TSchema extends TagSchema> = Entity<Tag, TSchema>\n\n/**\n * This resource lets you access articles in the YouTrack knowledge base.\n * https://www.jetbrains.com/help/youtrack/devportal/resource-api-articles.html\n */\nexport class ArticlesApi extends ResourceApi {\n /**\n * Gets all articles.\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.$top - Optional. Specifies the maximum number of entries that are returned in the response.\n * @param params.$skip - Optional. Specifies the number of returned entities to skip before returning the first one.\n * @returns The list of articles.\n */\n async getArticles<TSchema extends ArticleSchema>(\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<ArticleEntity<TSchema>[]> {\n return this.youtrack.fetch<ArticleEntity<TSchema>[]>(\n new RequestBuilder(\"api/articles\", { fields, ...queryParams(\"$top\", \"$skip\") }, params).get(),\n )\n }\n\n /**\n * Creates a new article.\n * @param body - Required fields: id (the database ID of the article to be linked as a sub-article).\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.draftId - ID of a draft to publish as a new article. If no draftId is provided, the article is created from scratch. In this case, you must specify the project in the request payload.\n * @param params.muteUpdateNotifications - Set to true if no notifications should be sent on changes made by this request.\n * @returns The created article.\n */\n async createArticle<TSchema extends ArticleSchema>(\n body: { id: string } | Partial<Article>,\n params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam & { draftId?: string },\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(\"api/articles\", { fields, ...queryParams(\"muteUpdateNotifications\", \"draftId\") }, params).post(\n body,\n ),\n )\n }\n\n /**\n * Reads an article with a specific ID.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The requested article.\n */\n async getArticle<TSchema extends ArticleSchema>(\n articleId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}`, { fields }, params).get(),\n )\n }\n\n /**\n * Updates a single article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param body - The updated article data.\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.muteUpdateNotifications - Set this parameter to true if no notifications should be sent on changes made by this request. This doesn't mute notifications sent by any workflow rules. Using this parameter requires Apply Commands Silently permission in all projects affected by the request.\n * @returns The updated article.\n */\n async updateArticle<TSchema extends ArticleSchema>(\n articleId: string,\n body: DeepPartial<Article>,\n params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}`, { fields, muteUpdateNotifications: \"string\" }, params).post(body),\n )\n }\n\n /**\n * Deletes an article. Note that this operation cannot be undone.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The deleted article.\n */\n async deleteArticle<TSchema extends ArticleSchema>(\n articleId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}`, { fields }, params).delete(),\n )\n }\n\n /**\n * Gets a list of all attachments to a specific article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param params.fields - A list of ArticleAttachment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.$top - Optional. Specifies the maximum number of entries that are returned in the response.\n * @param params.$skip - Optional. Specifies the number of returned entities to skip before returning the first one.\n * @returns The list of attachments for the specified article.\n */\n async getArticleAttachments<TSchema extends ArticleAttachmentSchema>(\n articleId: string,\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<ArticleAttachmentEntity<TSchema>[]> {\n return this.youtrack.fetch<ArticleAttachmentEntity<TSchema>[]>(\n new RequestBuilder(\n `api/articles/${articleId}/attachments`,\n { fields, ...queryParams(\"$top\", \"$skip\") },\n params,\n ).get(),\n )\n }\n\n /**\n * Adds an attachment to the article.\n * @param articleId - ID of the article to which the attachment will be added. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param body - A FormData object with attachment data.\n * @param params.fields - A list of ArticleAttachment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.muteUpdateNotifications - Set to true if no notifications should be sent on changes made by this request.\n * @returns The added attachment.\n */\n async createArticleAttachment<TSchema extends ArticleAttachmentSchema>(\n articleId: string,\n body: FormData,\n params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam,\n ): Promise<ArticleAttachmentEntity<TSchema>> {\n return this.youtrack.fetch<ArticleAttachmentEntity<TSchema>>(\n new RequestBuilder(\n `api/articles/${articleId}/attachments`,\n { fields, muteUpdateNotifications: \"string\" },\n params,\n ).postFile(body),\n )\n }\n\n /**\n * Reads a specific attachment in the article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param attachmentId - The database ID of the attachment.\n * @param params.fields - A list of ArticleAttachment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The requested article attachment.\n */\n async getArticleAttachment<TSchema extends ArticleAttachmentSchema>(\n articleId: string,\n attachmentId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleAttachmentEntity<TSchema>> {\n return this.youtrack.fetch<ArticleAttachmentEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/attachments/${attachmentId}`, { fields }, params).get(),\n )\n }\n\n /**\n * Updates a specific attachment in the article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param attachmentId - The database ID of the attachment.\n * @param body - The fields of the attachment to update.\n * @param params.fields - A list of ArticleAttachment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The updated article attachment.\n */\n async updateArticleAttachment<TSchema extends ArticleAttachmentSchema>(\n articleId: string,\n attachmentId: string,\n body: DeepPartial<ArticleAttachment>,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleAttachmentEntity<TSchema>> {\n return this.youtrack.fetch<ArticleAttachmentEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/attachments/${attachmentId}`, { fields }, params).post(body),\n )\n }\n\n /**\n * Deletes a specific attachment from the article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param attachmentId - The database ID of the attachment.\n * @param params.fields - A list of ArticleAttachment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The deleted article attachment.\n */\n async deleteArticleAttachment<TSchema extends ArticleAttachmentSchema>(\n articleId: string,\n attachmentId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<void> {\n return this.youtrack.fetch<void>(\n new RequestBuilder(`api/articles/${articleId}/attachments/${attachmentId}`, { fields }, params).delete(),\n )\n }\n\n /**\n * Gets the list of sub-articles of the current article.\n * @param articleId - ID of the parent article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.$top - Optional. Specifies the maximum number of entries that are returned in the response.\n * @param params.$skip - Optional. Specifies the number of returned entities to skip before returning the first one.\n * @returns The list of sub-articles.\n */\n async getChildArticles<TSchema extends ArticleSchema>(\n articleId: string,\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<ArticleEntity<TSchema>[]> {\n return this.youtrack.fetch<ArticleEntity<TSchema>[]>(\n new RequestBuilder(\n `api/articles/${articleId}/childArticles`,\n { fields, ...queryParams(\"$top\", \"$skip\") },\n params,\n ).get(),\n )\n }\n\n /**\n * Adds a new sub-article to the current article.\n * @param articleId - ID of the parent article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param body - Contains the ID of the sub-article to be linked.\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.muteUpdateNotifications - Optional. Set to true to mute notifications sent on changes made by this request.\n * @returns The updated parent article with the sub-article.\n */\n async addChildArticle<TSchema extends ArticleSchema>(\n articleId: string,\n body: { id: string } | Partial<Article>,\n params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(\n `api/articles/${articleId}/childArticles`,\n { fields, ...queryParams(\"muteUpdateNotifications\") },\n params,\n ).post(body),\n )\n }\n\n /**\n * Gets a specific sub-article of the current article.\n * @param articleId - Id of the parent article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param subArticleId - Id of the sub-article to retrieve.\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The requested sub-article.\n */\n async getChildArticle<TSchema extends ArticleSchema>(\n articleId: string,\n subArticleId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/childArticles/${subArticleId}`, { fields }, params).get(),\n )\n }\n\n /**\n * Updates a specific sub-article.\n * @param articleId - ID of the parent article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param subArticleId - ID of the sub-article to update.\n * @param body - The updated sub-article content.\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.muteUpdateNotifications - Set to true if no notifications should be sent on changes made by this request.\n * @returns The updated sub-article.\n */\n async updateChildArticle<TSchema extends ArticleSchema>(\n articleId: string,\n subArticleId: string,\n body: DeepPartial<Article>,\n params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(\n `api/articles/${articleId}/childArticles/${subArticleId}`,\n { fields, muteUpdateNotifications: \"boolean\" },\n params,\n ).post(body),\n )\n }\n\n /**\n * Removes the parent-child link between the specific sub-article and the current article.\n * This operation does not delete the specified sub-article.\n * @param articleId - ID of the parent article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param subArticleId - ID of the sub-article to unlink.\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The unlinked sub-article entity.\n */\n async removeChildArticleLink<TSchema extends ArticleSchema>(\n articleId: string,\n subArticleId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/childArticles/${subArticleId}`, { fields }, params).delete(),\n )\n }\n\n /**\n * Gets all accessible comments to a specific article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param params.fields - A list of ArticleComment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.$top - Optional. Specifies the maximum number of entries that are returned in the response.\n * @param params.$skip - Optional. Specifies the number of returned entities to skip before returning the first one.\n * @returns The list of article comments.\n */\n async getArticleComments<TSchema extends ArticleCommentSchema>(\n articleId: string,\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<ArticleCommentEntity<TSchema>[]> {\n return this.youtrack.fetch<ArticleCommentEntity<TSchema>[]>(\n new RequestBuilder(\n `api/articles/${articleId}/comments`,\n { fields, ...queryParams(\"$top\", \"$skip\") },\n params,\n ).get(),\n )\n }\n\n /**\n * Adds a new comment to the article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param body - Required fields: text.\n * @param params.fields - A list of ArticleComment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.draftId - Optional. The ID of an existing draft that should be published.\n * @param params.muteUpdateNotifications - Optional. Set this to true to suppress notifications on changes made by this request.\n * @returns The added comment.\n */\n async createArticleComment<TSchema extends ArticleCommentSchema>(\n articleId: string,\n body: { text: string } | DeepPartial<ArticleComment>,\n params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam & { draftId?: string },\n ): Promise<ArticleCommentEntity<TSchema>> {\n return this.youtrack.fetch<ArticleCommentEntity<TSchema>>(\n new RequestBuilder(\n `api/articles/${articleId}/comments`,\n { fields, ...queryParams(\"draftId\", \"muteUpdateNotifications\") },\n params,\n ).post(body),\n )\n }\n\n /**\n * Reads a comment with a specific ID.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param commentId - The database ID of the comment.\n * @param params.fields - A list of ArticleComment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The specified comment.\n */\n async getArticleComment<TSchema extends ArticleCommentSchema>(\n articleId: string,\n commentId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleCommentEntity<TSchema>> {\n return this.youtrack.fetch<ArticleCommentEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/comments/${commentId}`, { fields }, params).get(),\n )\n }\n\n /**\n * Updates an existing comment to a specific article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param commentId - The database ID of the comment.\n * @param body - Comment parameters\n * @param params.fields - A list of ArticleComment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.muteUpdateNotifications - Set this parameter to true if no notifications should be sent on changes made by this request.\n * @returns The updated comment.\n */\n async updateArticleComment<TSchema extends ArticleCommentSchema>(\n articleId: string,\n commentId: string,\n body: { text: string } | DeepPartial<ArticleComment>,\n params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam,\n ): Promise<ArticleCommentEntity<TSchema>> {\n return this.youtrack.fetch<ArticleCommentEntity<TSchema>>(\n new RequestBuilder(\n `api/articles/${articleId}/comments/${commentId}`,\n { fields, muteUpdateNotifications: \"boolean\" },\n params,\n ).post(body),\n )\n }\n\n /**\n * Deletes an existing comment to a specific article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param commentId - The database ID of the comment.\n * @param params.fields - A list of ArticleComment attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The deleted comment.\n */\n async deleteArticleComment<TSchema extends ArticleCommentSchema>(\n articleId: string,\n commentId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleCommentEntity<TSchema>> {\n return this.youtrack.fetch<ArticleCommentEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/comments/${commentId}`, { fields }, params).delete(),\n )\n }\n\n /**\n * Gets all accessible reactions to a specific article comment.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param commentId - The database ID of the comment.\n * @param params.fields - A list of Reaction attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.$top - Optional. Specifies the maximum number of entries that are returned in the response.\n * @param params.$skip - Optional. Specifies the number of returned entities to skip before returning the first one.\n * @returns The list of reactions to the comment.\n */\n async getArticleCommentReactions<TSchema extends ReactionSchema>(\n articleId: string,\n commentId: string,\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<ReactionEntity<TSchema>[]> {\n return this.youtrack.fetch<ReactionEntity<TSchema>[]>(\n new RequestBuilder(\n `api/articles/${articleId}/comments/${commentId}/reactions`,\n { fields, ...queryParams(\"$top\", \"$skip\") },\n params,\n ).get(),\n )\n }\n\n /**\n * Adds a new reaction to a comment with a specific ID.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param commentId - The database ID of the comment.\n * @param body - The reaction paramenters. Required fields: reaction.\n * @param params.fields - A list of Reaction attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The added reaction.\n */\n async createCommentReaction<TSchema extends ReactionSchema>(\n articleId: string,\n commentId: string,\n body: { reaction: string } | DeepPartial<Reaction>,\n params?: FieldsParam<TSchema>,\n ): Promise<ReactionEntity<TSchema>> {\n return this.youtrack.fetch<ReactionEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/comments/${commentId}/reactions`, { fields }, params).post(body),\n )\n }\n\n /**\n * Gets a reaction with a specific ID.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param commentId - The database ID of the comment.\n * @param reactionId - The database ID of the reaction.\n * @param params.fields - A list of Reaction attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The specified reaction.\n */\n async getCommnetReaction<TSchema extends ReactionSchema>(\n articleId: string,\n commentId: string,\n reactionId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ReactionEntity<TSchema>> {\n return this.youtrack.fetch<ReactionEntity<TSchema>>(\n new RequestBuilder(\n `api/articles/${articleId}/comments/${commentId}/reactions/${reactionId}`,\n { fields },\n params,\n ).get(),\n )\n }\n\n /**\n * Removes a reaction from a comment. Only the author of the reaction can remove it.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param commentId - The database ID of the comment.\n * @param reactionId - The database ID of the reaction.\n * @param params.fields - A list of Reaction attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The result of the delete operation.\n */\n async removeCommnetReaction<TSchema extends ReactionSchema>(\n articleId: string,\n commentId: string,\n reactionId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ReactionEntity<TSchema>> {\n return this.youtrack.fetch<ReactionEntity<TSchema>>(\n new RequestBuilder(\n `api/articles/${articleId}/comments/${commentId}/reactions/${reactionId}`,\n { fields },\n params,\n ).delete(),\n )\n }\n\n /**\n * Gets the article that is the parent for the current one.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param params.fields - A list of Article attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The parent article.\n */\n async getParentArticle<TSchema extends ArticleSchema>(\n articleId: string,\n params?: FieldsParam<TSchema>,\n ): Promise<ArticleEntity<TSchema>> {\n return this.youtrack.fetch<ArticleEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/parentArticle`, { fields }, params).get(),\n )\n }\n\n /**\n * Gets all tags added to the article that are visible to the current user.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param params.fields - A list of Tag attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @param params.$top - Optional. Specifies the maximum number of entries that are returned in the response.\n * @param params.$skip - Optional. Specifies the number of returned entities to skip before returning the first one.\n * @returns The list of tags.\n */\n async getArticleTags<TSchema extends TagSchema>(\n articleId: string,\n params?: ListParams & FieldsParam<TSchema>,\n ): Promise<TagEntity<TSchema>[]> {\n return this.youtrack.fetch<TagEntity<TSchema>[]>(\n new RequestBuilder(`api/articles/${articleId}/tags`, { fields, ...queryParams(\"$top\", \"$skip\") }, params).get(),\n )\n }\n\n /**\n * Tags the article with an existing tag.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (for example, NP-A-1).\n * @param body - Tag parameters. Required fields: id - the database ID of the tag.\n * @param params.fields - A list of Tag attributes that should be returned in the response. If no field is specified, only the entityId is returned.\n * @returns The tagged article with updated information.\n */\n async createArticleTag<TSchema extends TagSchema>(\n articleId: string,\n body: { id: string } | DeepPartial<Tag>,\n params?: FieldsParam<TSchema>,\n ): Promise<TagEntity<TSchema>> {\n return this.youtrack.fetch<TagEntity<TSchema>>(\n new RequestBuilder(`api/articles/${articleId}/tags`, { fields }, params).post(body),\n )\n }\n\n /**\n * Reads a specific tag added to the article.\n * @param articleId - ID of the article. You can specify either the database ID (for example, 226-0) or the article ID in the project (f