Skip to content

Commit

Permalink
bugfix, improve types
Browse files Browse the repository at this point in the history
  • Loading branch information
udamir committed Sep 22, 2024
1 parent 83fcb96 commit 1332de9
Show file tree
Hide file tree
Showing 14 changed files with 162 additions and 109 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const yt = YouTrack.client(baseUrl, token)

yt.Users.getCurrentUserProfile({
// fields in FieldsSchema format
fields: ["login", "avatarUrl", "email", "fullName"] as const
fields: ["login", "avatarUrl", "email", "fullName"]
}).then((user) => {
// typeof user
// { login: string, avatarUrl: string, email: string, fullName: string }
Expand Down Expand Up @@ -64,7 +64,7 @@ DashboardAddons.registerWidget(async (dashboardApi: DashboardApi, widgetApi: Wid

const yt = await YouTrack.widget(dashboardApi)
const user = await yt.Users.getCurrentUserProfile({
fields: ["login", "avatarUrl", "email", "fullName"] as const
fields: ["login", "avatarUrl", "email", "fullName"]
})
// typeof user
// { login: string, avatarUrl: string, email: string, fullName: string }
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "youtrack-client",
"description": "Client library for accessing the YouTrack REST and Widget API",
"version": "0.2.5",
"version": "0.2.6",
"type": "module",
"keywords": [
"youtrack",
Expand All @@ -17,7 +17,7 @@
"module": "dist/index.mjs",
"main": "dist/index.cjs",
"browser": "dist/youtrack-client.min.js",
"typings": "dist/index.d.ts",
"types": "dist/index.d.ts",
"files": [
"dist"
],
Expand All @@ -32,7 +32,8 @@
"prebuild": "rimraf ./dist",
"build": "rollup -c",
"check": "biome check",
"format": "biome format"
"format": "biome format",
"test:types": "tsd"
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
Expand Down
14 changes: 11 additions & 3 deletions src/resources/Activities.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import type { ActivityCursorPage, ActivityItem, Entity, FieldsParam, ListParams, Schema } from "../types"
import type {
ActivityCategory,
ActivityCursorPage,
ActivityItem,
Entity,
FieldsParam,
ListParams,
Schema,
} from "../types"
import { fields, queryParams, RequestBuilder } from "../utils"
import { ResourceApi } from "./common"

Expand All @@ -9,7 +17,7 @@ type ActivityItemEntity<TSchema extends ActivityItemSchema> = Entity<ActivityIte
type ActivityCursorPageEntity<TSchema extends ActivityCursorPageSchema> = Entity<ActivityCursorPage, TSchema>

type GetActivitiesParams = {
categories?: string[]
categories?: ActivityCategory[]
reverse?: boolean
start?: string
end?: string
Expand Down Expand Up @@ -87,7 +95,7 @@ export class ActivitiesApi extends ResourceApi {
* @returns A page of activities with pagination support, including cursors for navigation.
*/
async getActivitiesPage<TSchema extends ActivityCursorPageSchema>(
params: GetActivitiesPageParams & FieldsParam<TSchema>,
params?: GetActivitiesPageParams & FieldsParam<TSchema>,
): Promise<ActivityCursorPageEntity<TSchema>> {
// Perform the fetch request
return this.fetch<ActivityCursorPageEntity<TSchema>>(
Expand Down
4 changes: 2 additions & 2 deletions src/resources/Issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class IssuesApi extends ResourceApi {
async updateIssue<TSchema extends IssueSchema>(
issueId: string,
body: DeepPartial<Issue>,
params: FieldsParam<TSchema> & MuteUpdateNotificationsParam,
params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam,
): Promise<IssueEntity<TSchema>> {
return this.fetch<IssueEntity<TSchema>>(
...new RequestBuilder(`api/issues/${issueId}`, { fields, muteUpdateNotifications: "boolean" }, params).post(body),
Expand Down Expand Up @@ -213,7 +213,7 @@ export class IssuesApi extends ResourceApi {
*/
async getActivitiesPage<TSchema extends ActivityCursorPageSchema>(
issueId: string,
params: FieldsParam<TSchema> & {
params?: FieldsParam<TSchema> & {
categories: string
reverse?: boolean
start?: string
Expand Down
2 changes: 1 addition & 1 deletion src/resources/admin/Projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export class ProjectsApi extends ResourceApi {
projectId: string,
issueId: string,
body: DeepPartial<Issue>,
params: FieldsParam<TSchema> & MuteUpdateNotificationsParam,
params?: FieldsParam<TSchema> & MuteUpdateNotificationsParam,
): Promise<IssueEntity<TSchema>> {
return this.fetch<IssueEntity<TSchema>>(
...new RequestBuilder(
Expand Down
34 changes: 33 additions & 1 deletion src/types/entities/Activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,39 @@ export type ActivityCursorPage = EntityBase<"ActivityCursorPage"> & {
reverse: boolean // Indicates whether the order of returning activities on the page is from newest to oldest or the opposite. If false, then the oldest activity item that matches a selected filter is returned first. If true, then the newest activity is returned first. By default, false. Read-only.
}

export type SimpleValueActivityItem<TCategory extends string, TValueType> = BaseActivityItem<TCategory, TValueType, any>
export type ActivityCategory =
| "ArticleCommentAttachmentsCategory"
| "ArticleTagsCategory"
| "AttachmentRecognizedTextCategory"
| "AttachmentRenameCategory"
| "AttachmentVisibilityCategory"
| "AttachmentsCategory"
| "CommentAttachmentsCategory"
| "CommentTextCategory"
| "CommentUsesMarkdownCategory"
| "CommentVisibilityCategory"
| "CommentsCategory"
| "CustomFieldCategory"
| "DescriptionCategory"
| "IssueCreatedCategory"
| "IssueResolvedCategory"
| "IssueUsesMarkdownCategory"
| "IssueVisibilityCategory"
| "LinksCategory"
| "ProjectCategory"
| "SprintCategory"
| "SummaryCategory"
| "TagsCategory"
| "TotalVotesCategory"
| "VcsChangeCategory"
| "VcsChangeStateCategory"
| "VotersCategory"

export type SimpleValueActivityItem<TCategory extends ActivityCategory, TValueType> = BaseActivityItem<
TCategory,
TValueType,
any
>

export type CommentAttachmentsActivityItem = BaseActivityItem<
"ArticleCommentAttachmentsCategory" | "CommentAttachmentsCategory",
Expand Down
6 changes: 5 additions & 1 deletion src/types/entities/Issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export type IssueCustomField =
| DateIssueCustomField
| PeriodIssueCustomField
| SingleBuildIssueCustomField
| SingleEnumIssueCustomField
| SingleGroupIssueCustomField
| SingleOwnedIssueCustomField
| SingleUserIssueCustomField
Expand All @@ -80,7 +81,6 @@ export type IssueCustomField =
| StateMachineIssueCustomField
| MultiBuildIssueCustomField
| MultiEnumIssueCustomField
| MultiEnumIssueCustomField
| MultiGroupIssueCustomField
| MultiOwnedIssueCustomField
| MultiUserIssueCustomField
Expand Down Expand Up @@ -121,6 +121,10 @@ export type SingleOwnedIssueCustomField = IssueCustomFieldBase<"SingleOwnedIssue
value: OwnedBundleElement // The value assigned to the custom field in the issue
}

export type SingleEnumIssueCustomField = IssueCustomFieldBase<"SingleEnumIssueCustomField"> & {
value: EnumBundleElement // The value assigned to the custom field in the issue
}

export type SingleUserIssueCustomField = IssueCustomFieldBase<"SingleUserIssueCustomField"> & {
value: User // The value assigned to the custom field in the issue
}
Expand Down
2 changes: 1 addition & 1 deletion src/types/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export type FetchApiConfig = {
method?: "POST" | "GET" | "PATCH" | "PUT" | "DELETE"
headers?: Record<string, string>
body?: string | FormData
body?: string | object | FormData
[key: string]: unknown
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ type FindName<T, Name extends string = ""> = T extends `${Name}${infer Char}${in
*
* Example:
* - Input: `"id,name),rest"`
* - Output: `[[{ topic: ["id", "name"] }], ",rest"]`
* - Output: `[["id", "name"], ",rest"]`
*
* @template T - The input string to parse into a schema.
* @template Items - The accumulator for parsed schema items, defaulting to an empty array.
Expand Down
12 changes: 12 additions & 0 deletions src/utils/fetchHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import type { FieldsSchema, QueryParamBuilder, Schema } from "../types"
import { isObject } from "./common"

export const encodeBody = (data?: string | object | FormData): string | FormData | undefined => {
if (data instanceof FormData) {
return data
}

if (typeof data === "object") {
return JSON.stringify(data)
}

return data
}

// Function to build the URI with path parameters
export const buildUri = (baseUri: string, pathParams: Record<string, string> = {}): string =>
Object.keys(pathParams).reduce(
Expand Down
6 changes: 3 additions & 3 deletions src/utils/queryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ export class RequestBuilder<T extends Record<string, any>> {
return this.build()
}

public post<TBody>(body: TBody) {
return this.build({ method: "POST", body: JSON.stringify(body) })
public post<TBody extends object>(body: TBody) {
return this.build({ method: "POST", body })
}

public postFile(body: FormData) {
return this.build({ method: "POST", body, "Content-Type": "multipart/form-data" })
return this.build({ method: "POST", body, headers: { "Content-Type": "multipart/form-data" } })
}

public delete() {
Expand Down
15 changes: 9 additions & 6 deletions src/youtrack.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { DashboardApi, FetchApi, Service } from "./types"
import * as ResourceApi from "./resources"
import { joinUrl } from "./utils"
import { encodeBody, joinUrl } from "./utils"

export class YouTrack {
public Agiles: ResourceApi.AgilesApi
Expand Down Expand Up @@ -38,16 +38,19 @@ export class YouTrack {
}

static client(baseUrl: string, token: string) {
return new YouTrack(async (url, options?) => {
const response = await fetch(joinUrl(baseUrl, url), {
return new YouTrack(async (url, options = {}) => {
const { body, headers, ...rest } = options
const params = {
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json",
"Content-Type": "application/json",
...options?.headers,
...headers,
},
...options,
})
...(body ? { body: encodeBody(body) } : {}),
...rest,
}
const response = await fetch(joinUrl(baseUrl, url), params)

if (!response.ok) {
throw new Error(`Error: ${response.status} ${response.statusText}`)
Expand Down
Loading

0 comments on commit 1332de9

Please sign in to comment.