gogs-client.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. /**
  2. * Gogs API Client
  3. * Provides methods to interact with a Gogs server REST API
  4. */
  5. import axios, { AxiosInstance } from 'axios';
  6. import type {
  7. GogsUser,
  8. GogsRepository,
  9. GogsSearchResponse,
  10. GogsFileContent,
  11. GogsBranch,
  12. GogsCommit,
  13. GogsConfig,
  14. GogsIssue,
  15. GogsIssueComment,
  16. GogsLabel,
  17. GogsMilestone,
  18. GogsOrganization,
  19. GogsTeam,
  20. GogsTree,
  21. GogsRelease,
  22. GogsCollaborator,
  23. GogsEmail,
  24. GogsPublicKey,
  25. GogsWebhook,
  26. GogsWebhookEvent,
  27. GogsWebhookType,
  28. GogsWebhookConfig,
  29. GogsFollower,
  30. } from './types.js';
  31. export class GogsClient {
  32. private client: AxiosInstance;
  33. private serverUrl: string;
  34. constructor(config: GogsConfig) {
  35. this.serverUrl = config.serverUrl.replace(/\/$/, '');
  36. this.client = axios.create({
  37. baseURL: `${this.serverUrl}/api/v1`,
  38. headers: {
  39. 'Content-Type': 'application/json',
  40. ...(config.accessToken && { Authorization: `token ${config.accessToken}` }),
  41. },
  42. });
  43. }
  44. /**
  45. * Get information about the authenticated user
  46. */
  47. async getCurrentUser(): Promise<GogsUser> {
  48. const response = await this.client.get<GogsUser>('/user');
  49. return response.data;
  50. }
  51. /**
  52. * Get information about a specific user
  53. */
  54. async getUser(username: string): Promise<GogsUser> {
  55. const response = await this.client.get<GogsUser>(`/users/${username}`);
  56. return response.data;
  57. }
  58. /**
  59. * Search for users
  60. */
  61. async searchUsers(query: string, limit: number = 10): Promise<GogsUser[]> {
  62. const response = await this.client.get<GogsSearchResponse<GogsUser>>('/users/search', {
  63. params: { q: query, limit },
  64. });
  65. return response.data.data;
  66. }
  67. /**
  68. * List repositories for the authenticated user
  69. */
  70. async listMyRepositories(): Promise<GogsRepository[]> {
  71. const response = await this.client.get<GogsRepository[]>('/user/repos');
  72. return response.data;
  73. }
  74. /**
  75. * List repositories for a specific user
  76. */
  77. async listUserRepositories(username: string): Promise<GogsRepository[]> {
  78. const response = await this.client.get<GogsRepository[]>(`/users/${username}/repos`);
  79. return response.data;
  80. }
  81. /**
  82. * Search for repositories
  83. */
  84. async searchRepositories(
  85. query: string,
  86. options?: { uid?: number; limit?: number; page?: number }
  87. ): Promise<GogsRepository[]> {
  88. const response = await this.client.get<GogsSearchResponse<GogsRepository>>('/repos/search', {
  89. params: {
  90. q: query,
  91. uid: options?.uid || 0,
  92. limit: options?.limit || 10,
  93. page: options?.page || 1,
  94. },
  95. });
  96. return response.data.data;
  97. }
  98. /**
  99. * Get information about a specific repository
  100. */
  101. async getRepository(owner: string, repo: string): Promise<GogsRepository> {
  102. const response = await this.client.get<GogsRepository>(`/repos/${owner}/${repo}`);
  103. return response.data;
  104. }
  105. /**
  106. * Create a new repository
  107. */
  108. async createRepository(data: {
  109. name: string;
  110. description?: string;
  111. private?: boolean;
  112. auto_init?: boolean;
  113. gitignores?: string;
  114. license?: string;
  115. readme?: string;
  116. }): Promise<GogsRepository> {
  117. const response = await this.client.post<GogsRepository>('/user/repos', data);
  118. return response.data;
  119. }
  120. /**
  121. * Delete a repository
  122. */
  123. async deleteRepository(owner: string, repo: string): Promise<void> {
  124. await this.client.delete(`/repos/${owner}/${repo}`);
  125. }
  126. /**
  127. * Get file or directory contents
  128. */
  129. async getContents(
  130. owner: string,
  131. repo: string,
  132. path: string,
  133. ref?: string
  134. ): Promise<GogsFileContent | GogsFileContent[]> {
  135. const response = await this.client.get<GogsFileContent | GogsFileContent[]>(
  136. `/repos/${owner}/${repo}/contents/${path}`,
  137. {
  138. params: ref ? { ref } : undefined,
  139. }
  140. );
  141. return response.data;
  142. }
  143. /**
  144. * Get raw file content
  145. */
  146. async getRawContent(owner: string, repo: string, ref: string, path: string): Promise<string> {
  147. const response = await this.client.get<string>(
  148. `/repos/${owner}/${repo}/raw/${ref}/${path}`,
  149. {
  150. responseType: 'text',
  151. }
  152. );
  153. return response.data;
  154. }
  155. /**
  156. * List branches in a repository
  157. */
  158. async listBranches(owner: string, repo: string): Promise<GogsBranch[]> {
  159. const response = await this.client.get<GogsBranch[]>(`/repos/${owner}/${repo}/branches`);
  160. return response.data;
  161. }
  162. /**
  163. * Get commits from a repository
  164. */
  165. async getCommits(
  166. owner: string,
  167. repo: string,
  168. options?: { sha?: string; page?: number }
  169. ): Promise<GogsCommit[]> {
  170. const response = await this.client.get<GogsCommit[]>(`/repos/${owner}/${repo}/commits`, {
  171. params: {
  172. sha: options?.sha,
  173. page: options?.page || 1,
  174. },
  175. });
  176. return response.data;
  177. }
  178. /**
  179. * Get a git tree by SHA
  180. */
  181. async getTree(owner: string, repo: string, sha: string): Promise<GogsTree> {
  182. const response = await this.client.get<GogsTree>(`/repos/${owner}/${repo}/git/trees/${sha}`);
  183. return response.data;
  184. }
  185. /**
  186. * List issues in a repository
  187. */
  188. async listIssues(
  189. owner: string,
  190. repo: string,
  191. options?: {
  192. state?: 'open' | 'closed' | 'all';
  193. labels?: string;
  194. page?: number;
  195. per_page?: number;
  196. }
  197. ): Promise<GogsIssue[]> {
  198. const response = await this.client.get<GogsIssue[]>(`/repos/${owner}/${repo}/issues`, {
  199. params: {
  200. state: options?.state || 'open',
  201. labels: options?.labels,
  202. page: options?.page || 1,
  203. per_page: options?.per_page || 30,
  204. },
  205. });
  206. return response.data;
  207. }
  208. /**
  209. * Get a specific issue
  210. */
  211. async getIssue(owner: string, repo: string, number: number): Promise<GogsIssue> {
  212. const response = await this.client.get<GogsIssue>(`/repos/${owner}/${repo}/issues/${number}`);
  213. return response.data;
  214. }
  215. /**
  216. * Create a new issue
  217. */
  218. async createIssue(
  219. owner: string,
  220. repo: string,
  221. data: {
  222. title: string;
  223. body?: string;
  224. assignee?: string;
  225. milestone?: number;
  226. labels?: number[];
  227. }
  228. ): Promise<GogsIssue> {
  229. const response = await this.client.post<GogsIssue>(
  230. `/repos/${owner}/${repo}/issues`,
  231. data
  232. );
  233. return response.data;
  234. }
  235. /**
  236. * Update an existing issue
  237. */
  238. async updateIssue(
  239. owner: string,
  240. repo: string,
  241. number: number,
  242. data: {
  243. title?: string;
  244. body?: string;
  245. assignee?: string;
  246. milestone?: number;
  247. state?: 'open' | 'closed';
  248. labels?: number[];
  249. }
  250. ): Promise<GogsIssue> {
  251. const response = await this.client.patch<GogsIssue>(
  252. `/repos/${owner}/${repo}/issues/${number}`,
  253. data
  254. );
  255. return response.data;
  256. }
  257. /**
  258. * List comments on an issue
  259. */
  260. async listIssueComments(
  261. owner: string,
  262. repo: string,
  263. number: number
  264. ): Promise<GogsIssueComment[]> {
  265. const response = await this.client.get<GogsIssueComment[]>(
  266. `/repos/${owner}/${repo}/issues/${number}/comments`
  267. );
  268. return response.data;
  269. }
  270. /**
  271. * Create a comment on an issue
  272. */
  273. async createIssueComment(
  274. owner: string,
  275. repo: string,
  276. number: number,
  277. body: string
  278. ): Promise<GogsIssueComment> {
  279. const response = await this.client.post<GogsIssueComment>(
  280. `/repos/${owner}/${repo}/issues/${number}/comments`,
  281. { body }
  282. );
  283. return response.data;
  284. }
  285. /**
  286. * Edit a comment on an issue
  287. */
  288. async updateIssueComment(
  289. owner: string,
  290. repo: string,
  291. commentId: number,
  292. body: string
  293. ): Promise<GogsIssueComment> {
  294. const response = await this.client.patch<GogsIssueComment>(
  295. `/repos/${owner}/${repo}/issues/comments/${commentId}`,
  296. { body }
  297. );
  298. return response.data;
  299. }
  300. /**
  301. * List all labels in a repository
  302. */
  303. async listLabels(owner: string, repo: string): Promise<GogsLabel[]> {
  304. const response = await this.client.get<GogsLabel[]>(`/repos/${owner}/${repo}/labels`);
  305. return response.data;
  306. }
  307. /**
  308. * Get a specific label by ID
  309. */
  310. async getLabel(owner: string, repo: string, labelId: number): Promise<GogsLabel> {
  311. const response = await this.client.get<GogsLabel>(`/repos/${owner}/${repo}/labels/${labelId}`);
  312. return response.data;
  313. }
  314. /**
  315. * Create a new label
  316. */
  317. async createLabel(
  318. owner: string,
  319. repo: string,
  320. data: {
  321. name: string;
  322. color: string;
  323. }
  324. ): Promise<GogsLabel> {
  325. const response = await this.client.post<GogsLabel>(
  326. `/repos/${owner}/${repo}/labels`,
  327. data
  328. );
  329. return response.data;
  330. }
  331. /**
  332. * Update an existing label
  333. */
  334. async updateLabel(
  335. owner: string,
  336. repo: string,
  337. labelId: number,
  338. data: {
  339. name?: string;
  340. color?: string;
  341. }
  342. ): Promise<GogsLabel> {
  343. const response = await this.client.patch<GogsLabel>(
  344. `/repos/${owner}/${repo}/labels/${labelId}`,
  345. data
  346. );
  347. return response.data;
  348. }
  349. /**
  350. * Delete a label
  351. */
  352. async deleteLabel(owner: string, repo: string, labelId: number): Promise<void> {
  353. await this.client.delete(`/repos/${owner}/${repo}/labels/${labelId}`);
  354. }
  355. /**
  356. * List labels on a specific issue
  357. */
  358. async listIssueLabels(owner: string, repo: string, issueNumber: number): Promise<GogsLabel[]> {
  359. const response = await this.client.get<GogsLabel[]>(
  360. `/repos/${owner}/${repo}/issues/${issueNumber}/labels`
  361. );
  362. return response.data;
  363. }
  364. /**
  365. * Add labels to an issue
  366. */
  367. async addIssueLabels(
  368. owner: string,
  369. repo: string,
  370. issueNumber: number,
  371. labelIds: number[]
  372. ): Promise<GogsLabel[]> {
  373. const response = await this.client.post<GogsLabel[]>(
  374. `/repos/${owner}/${repo}/issues/${issueNumber}/labels`,
  375. { labels: labelIds }
  376. );
  377. return response.data;
  378. }
  379. /**
  380. * Remove a label from an issue
  381. */
  382. async removeIssueLabel(
  383. owner: string,
  384. repo: string,
  385. issueNumber: number,
  386. labelId: number
  387. ): Promise<void> {
  388. await this.client.delete(`/repos/${owner}/${repo}/issues/${issueNumber}/labels/${labelId}`);
  389. }
  390. /**
  391. * Replace all labels on an issue
  392. */
  393. async replaceIssueLabels(
  394. owner: string,
  395. repo: string,
  396. issueNumber: number,
  397. labelIds: number[]
  398. ): Promise<GogsLabel[]> {
  399. const response = await this.client.put<GogsLabel[]>(
  400. `/repos/${owner}/${repo}/issues/${issueNumber}/labels`,
  401. { labels: labelIds }
  402. );
  403. return response.data;
  404. }
  405. /**
  406. * Remove all labels from an issue
  407. */
  408. async removeAllIssueLabels(
  409. owner: string,
  410. repo: string,
  411. issueNumber: number
  412. ): Promise<void> {
  413. await this.client.delete(`/repos/${owner}/${repo}/issues/${issueNumber}/labels`);
  414. }
  415. /**
  416. * List all milestones in a repository
  417. */
  418. async listMilestones(owner: string, repo: string): Promise<GogsMilestone[]> {
  419. const response = await this.client.get<GogsMilestone[]>(`/repos/${owner}/${repo}/milestones`);
  420. return response.data;
  421. }
  422. /**
  423. * Get a specific milestone by ID
  424. */
  425. async getMilestone(owner: string, repo: string, milestoneId: number): Promise<GogsMilestone> {
  426. const response = await this.client.get<GogsMilestone>(`/repos/${owner}/${repo}/milestones/${milestoneId}`);
  427. return response.data;
  428. }
  429. /**
  430. * Create a new milestone
  431. */
  432. async createMilestone(
  433. owner: string,
  434. repo: string,
  435. data: {
  436. title: string;
  437. description?: string;
  438. due_on?: string;
  439. }
  440. ): Promise<GogsMilestone> {
  441. const response = await this.client.post<GogsMilestone>(
  442. `/repos/${owner}/${repo}/milestones`,
  443. data
  444. );
  445. return response.data;
  446. }
  447. /**
  448. * Update an existing milestone
  449. */
  450. async updateMilestone(
  451. owner: string,
  452. repo: string,
  453. milestoneId: number,
  454. data: {
  455. title?: string;
  456. description?: string;
  457. due_on?: string;
  458. state?: 'open' | 'closed';
  459. }
  460. ): Promise<GogsMilestone> {
  461. const response = await this.client.patch<GogsMilestone>(
  462. `/repos/${owner}/${repo}/milestones/${milestoneId}`,
  463. data
  464. );
  465. return response.data;
  466. }
  467. /**
  468. * Delete a milestone
  469. */
  470. async deleteMilestone(owner: string, repo: string, milestoneId: number): Promise<void> {
  471. await this.client.delete(`/repos/${owner}/${repo}/milestones/${milestoneId}`);
  472. }
  473. /**
  474. * List organizations for the authenticated user
  475. */
  476. async listUserOrganizations(): Promise<GogsOrganization[]> {
  477. const response = await this.client.get<GogsOrganization[]>('/user/orgs');
  478. return response.data;
  479. }
  480. /**
  481. * Create a new organization
  482. */
  483. async createOrganization(data: {
  484. username: string;
  485. full_name?: string;
  486. description?: string;
  487. website?: string;
  488. location?: string;
  489. }): Promise<GogsOrganization> {
  490. const response = await this.client.post<GogsOrganization>('/user/orgs', data);
  491. return response.data;
  492. }
  493. /**
  494. * List public organizations for a specific user
  495. */
  496. async listPublicOrganizations(username: string): Promise<GogsOrganization[]> {
  497. const response = await this.client.get<GogsOrganization[]>(`/users/${username}/orgs`);
  498. return response.data;
  499. }
  500. /**
  501. * Get information about a specific organization
  502. */
  503. async getOrganization(orgname: string): Promise<GogsOrganization> {
  504. const response = await this.client.get<GogsOrganization>(`/orgs/${orgname}`);
  505. return response.data;
  506. }
  507. /**
  508. * Update an organization
  509. */
  510. async updateOrganization(
  511. orgname: string,
  512. data: {
  513. full_name?: string;
  514. description?: string;
  515. website?: string;
  516. location?: string;
  517. }
  518. ): Promise<GogsOrganization> {
  519. const response = await this.client.patch<GogsOrganization>(`/orgs/${orgname}`, data);
  520. return response.data;
  521. }
  522. /**
  523. * Add or update organization membership
  524. */
  525. async addOrganizationMember(
  526. orgname: string,
  527. username: string,
  528. role: 'admin' | 'member'
  529. ): Promise<void> {
  530. await this.client.put(`/orgs/${orgname}/memberships/${username}`, { role });
  531. }
  532. /**
  533. * List teams in an organization
  534. */
  535. async listOrganizationTeams(orgname: string): Promise<GogsTeam[]> {
  536. const response = await this.client.get<GogsTeam[]>(`/orgs/${orgname}/teams`);
  537. return response.data;
  538. }
  539. /**
  540. * Create a new team in an organization
  541. */
  542. async createTeam(
  543. orgname: string,
  544. data: {
  545. name: string;
  546. description?: string;
  547. permission?: 'read' | 'write' | 'admin';
  548. }
  549. ): Promise<GogsTeam> {
  550. const response = await this.client.post<GogsTeam>(
  551. `/admin/orgs/${orgname}/teams`,
  552. data
  553. );
  554. return response.data;
  555. }
  556. /**
  557. * Get a specific team by ID
  558. */
  559. async getTeam(teamId: number): Promise<GogsTeam> {
  560. const response = await this.client.get<GogsTeam>(`/teams/${teamId}`);
  561. return response.data;
  562. }
  563. /**
  564. * Add a user to a team
  565. */
  566. async addTeamMember(teamId: number, username: string): Promise<void> {
  567. await this.client.put(`/admin/teams/${teamId}/members/${username}`);
  568. }
  569. /**
  570. * Remove a user from a team
  571. */
  572. async removeTeamMember(teamId: number, username: string): Promise<void> {
  573. await this.client.delete(`/admin/teams/${teamId}/members/${username}`);
  574. }
  575. /**
  576. * List releases for a repository
  577. */
  578. async listReleases(owner: string, repo: string): Promise<GogsRelease[]> {
  579. const response = await this.client.get<GogsRelease[]>(`/repos/${owner}/${repo}/releases`);
  580. return response.data;
  581. }
  582. /**
  583. * List collaborators for a repository
  584. */
  585. async listCollaborators(owner: string, repo: string): Promise<GogsCollaborator[]> {
  586. const response = await this.client.get<GogsCollaborator[]>(
  587. `/repos/${owner}/${repo}/collaborators`
  588. );
  589. return response.data;
  590. }
  591. /**
  592. * Check if a user is a collaborator
  593. */
  594. async checkCollaborator(owner: string, repo: string, username: string): Promise<boolean> {
  595. try {
  596. await this.client.get(`/repos/${owner}/${repo}/collaborators/${username}`);
  597. return true;
  598. } catch (error) {
  599. if (axios.isAxiosError(error) && error.response?.status === 404) {
  600. return false;
  601. }
  602. throw error;
  603. }
  604. }
  605. /**
  606. * Add a collaborator to a repository
  607. */
  608. async addCollaborator(
  609. owner: string,
  610. repo: string,
  611. username: string,
  612. permission?: 'read' | 'write' | 'admin'
  613. ): Promise<void> {
  614. await this.client.put(`/repos/${owner}/${repo}/collaborators/${username}`, {
  615. permission: permission || 'write',
  616. });
  617. }
  618. /**
  619. * Remove a collaborator from a repository
  620. */
  621. async removeCollaborator(owner: string, repo: string, username: string): Promise<void> {
  622. await this.client.delete(`/repos/${owner}/${repo}/collaborators/${username}`);
  623. }
  624. /**
  625. * List email addresses for the authenticated user
  626. */
  627. async listUserEmails(): Promise<GogsEmail[]> {
  628. const response = await this.client.get<GogsEmail[]>('/user/emails');
  629. return response.data;
  630. }
  631. /**
  632. * Add email address(es) to the authenticated user's account
  633. */
  634. async addUserEmails(emails: string[]): Promise<GogsEmail[]> {
  635. const response = await this.client.post<GogsEmail[]>('/user/emails', { emails });
  636. return response.data;
  637. }
  638. /**
  639. * Delete email address(es) from the authenticated user's account
  640. */
  641. async deleteUserEmails(emails: string[]): Promise<void> {
  642. await this.client.delete('/user/emails', { data: { emails } });
  643. }
  644. /**
  645. * List public keys for a specific user
  646. */
  647. async listUserKeys(username: string): Promise<GogsPublicKey[]> {
  648. const response = await this.client.get<GogsPublicKey[]>(`/users/${username}/keys`);
  649. return response.data;
  650. }
  651. /**
  652. * List public keys for the authenticated user
  653. */
  654. async listMyKeys(): Promise<GogsPublicKey[]> {
  655. const response = await this.client.get<GogsPublicKey[]>('/user/keys');
  656. return response.data;
  657. }
  658. /**
  659. * Get a single public key by ID
  660. */
  661. async getPublicKey(keyId: number): Promise<GogsPublicKey> {
  662. const response = await this.client.get<GogsPublicKey>(`/user/keys/${keyId}`);
  663. return response.data;
  664. }
  665. /**
  666. * Create a new public key for the authenticated user
  667. */
  668. async createPublicKey(data: {
  669. title: string;
  670. key: string;
  671. }): Promise<GogsPublicKey> {
  672. const response = await this.client.post<GogsPublicKey>('/user/keys', data);
  673. return response.data;
  674. }
  675. /**
  676. * Delete a public key by ID
  677. */
  678. async deletePublicKey(keyId: number): Promise<void> {
  679. await this.client.delete(`/user/keys/${keyId}`);
  680. }
  681. /**
  682. * List webhooks for a repository
  683. */
  684. async listHooks(owner: string, repo: string): Promise<GogsWebhook[]> {
  685. const response = await this.client.get<GogsWebhook[]>(`/repos/${owner}/${repo}/hooks`);
  686. return response.data;
  687. }
  688. /**
  689. * Create a new webhook for a repository
  690. */
  691. async createHook(
  692. owner: string,
  693. repo: string,
  694. data: {
  695. type: GogsWebhookType;
  696. config: GogsWebhookConfig;
  697. events?: GogsWebhookEvent[];
  698. active?: boolean;
  699. }
  700. ): Promise<GogsWebhook> {
  701. const response = await this.client.post<GogsWebhook>(
  702. `/repos/${owner}/${repo}/hooks`,
  703. data
  704. );
  705. return response.data;
  706. }
  707. /**
  708. * Update an existing webhook
  709. */
  710. async updateHook(
  711. owner: string,
  712. repo: string,
  713. hookId: number,
  714. data: {
  715. config: GogsWebhookConfig;
  716. events?: GogsWebhookEvent[];
  717. active?: boolean;
  718. }
  719. ): Promise<GogsWebhook> {
  720. const response = await this.client.patch<GogsWebhook>(
  721. `/repos/${owner}/${repo}/hooks/${hookId}`,
  722. data
  723. );
  724. return response.data;
  725. }
  726. /**
  727. * Delete a webhook from a repository
  728. */
  729. async deleteHook(owner: string, repo: string, hookId: number): Promise<void> {
  730. await this.client.delete(`/repos/${owner}/${repo}/hooks/${hookId}`);
  731. }
  732. /**
  733. * List followers of a user
  734. */
  735. async listFollowers(username: string): Promise<GogsFollower[]> {
  736. const response = await this.client.get<GogsFollower[]>(`/users/${username}/followers`);
  737. return response.data;
  738. }
  739. /**
  740. * List users that a user is following
  741. */
  742. async listFollowing(username: string): Promise<GogsFollower[]> {
  743. const response = await this.client.get<GogsFollower[]>(`/users/${username}/following`);
  744. return response.data;
  745. }
  746. /**
  747. * Check if the authenticated user is following a target user
  748. */
  749. async checkFollowing(username: string): Promise<boolean> {
  750. try {
  751. await this.client.get(`/user/following/${username}`);
  752. return true;
  753. } catch (error) {
  754. if (axios.isAxiosError(error) && error.response?.status === 404) {
  755. return false;
  756. }
  757. throw error;
  758. }
  759. }
  760. /**
  761. * Follow a user (authenticated user follows the target user)
  762. */
  763. async followUser(username: string): Promise<void> {
  764. await this.client.put(`/user/following/${username}`);
  765. }
  766. /**
  767. * Unfollow a user (authenticated user unfollows the target user)
  768. */
  769. async unfollowUser(username: string): Promise<void> {
  770. await this.client.delete(`/user/following/${username}`);
  771. }
  772. }