# @apiclient.xyz/gitea A TypeScript client for the Gitea API, providing typed access to repositories, organizations, secrets management, and Gitea Actions workflow runs. ## Install ```sh npm install @apiclient.xyz/gitea # or pnpm install @apiclient.xyz/gitea ``` ## Usage All examples below use ESM imports and top-level `await`. The package ships as a pure ESM module with full TypeScript type declarations. ### Creating a Client ```typescript import { GiteaClient } from '@apiclient.xyz/gitea'; const client = new GiteaClient('https://gitea.example.com', 'your-api-token'); ``` The `baseUrl` should point to your Gitea instance root (trailing slashes are stripped automatically). The `token` is an API token generated in Gitea under **Settings > Applications**. ### Testing the Connection ```typescript const result = await client.testConnection(); if (result.ok) { console.log('Connected successfully.'); } else { console.error('Connection failed:', result.error); } ``` ### Listing Repositories ```typescript // Fetch the first page of repositories (default: 50 per page, sorted by updated) const repos = await client.getRepos(); // Search with pagination const results = await client.getRepos({ search: 'my-project', page: 1, perPage: 20, }); for (const repo of results) { console.log(`${repo.full_name} - ${repo.description}`); } ``` ### Listing Organizations ```typescript const orgs = await client.getOrgs(); for (const org of orgs) { console.log(`${org.name} (${org.repo_count} repos)`); } // With pagination const page2 = await client.getOrgs({ page: 2, perPage: 10 }); ``` ### Managing Repository Secrets ```typescript const ownerRepo = 'my-org/my-repo'; // List all secrets for a repository const secrets = await client.getRepoSecrets(ownerRepo); for (const secret of secrets) { console.log(`${secret.name} (created ${secret.created_at})`); } // Create or update a secret await client.setRepoSecret(ownerRepo, 'DEPLOY_TOKEN', 's3cret-value'); // Delete a secret await client.deleteRepoSecret(ownerRepo, 'DEPLOY_TOKEN'); ``` ### Managing Organization Secrets ```typescript const orgName = 'my-org'; // List all secrets for an organization const orgSecrets = await client.getOrgSecrets(orgName); // Create or update an organization-level secret await client.setOrgSecret(orgName, 'NPM_TOKEN', 'npm_abc123'); // Delete an organization-level secret await client.deleteOrgSecret(orgName, 'NPM_TOKEN'); ``` ### Working with Action Runs ```typescript const ownerRepo = 'my-org/my-repo'; // List recent action runs const runs = await client.getActionRuns(ownerRepo); for (const run of runs) { console.log(`#${run.id} ${run.name} [${run.status}/${run.conclusion}] on ${run.head_branch}`); } // Paginate runs const olderRuns = await client.getActionRuns(ownerRepo, { page: 2, perPage: 10 }); // Get jobs for a specific run const jobs = await client.getActionRunJobs(ownerRepo, runs[0].id); for (const job of jobs) { console.log(` Job "${job.name}" - ${job.status} (${job.run_duration}s)`); } // Fetch raw log output for a job const log = await client.getJobLog(ownerRepo, jobs[0].id); console.log(log); // Re-run a workflow await client.rerunAction(ownerRepo, runs[0].id); // Cancel a running workflow await client.cancelAction(ownerRepo, runs[0].id); ``` ## API Reference ### `GiteaClient` | Method | Signature | Returns | Description | |--------|-----------|---------|-------------| | `constructor` | `(baseUrl: string, token: string)` | `GiteaClient` | Create a new client instance. | | `testConnection` | `()` | `Promise` | Verify credentials and connectivity. | | `getRepos` | `(opts?: IListOptions)` | `Promise` | Search/list repositories with pagination. | | `getOrgs` | `(opts?: IListOptions)` | `Promise` | List organizations with pagination. | | `getRepoSecrets` | `(ownerRepo: string)` | `Promise` | List all action secrets for a repository. | | `setRepoSecret` | `(ownerRepo: string, key: string, value: string)` | `Promise` | Create or update a repository secret. | | `deleteRepoSecret` | `(ownerRepo: string, key: string)` | `Promise` | Delete a repository secret. | | `getOrgSecrets` | `(orgName: string)` | `Promise` | List all action secrets for an organization. | | `setOrgSecret` | `(orgName: string, key: string, value: string)` | `Promise` | Create or update an organization secret. | | `deleteOrgSecret` | `(orgName: string, key: string)` | `Promise` | Delete an organization secret. | | `getActionRuns` | `(ownerRepo: string, opts?: IListOptions)` | `Promise` | List action workflow runs for a repository. | | `getActionRunJobs` | `(ownerRepo: string, runId: number)` | `Promise` | List jobs within a specific action run. | | `getJobLog` | `(ownerRepo: string, jobId: number)` | `Promise` | Fetch the raw log output for a job. | | `rerunAction` | `(ownerRepo: string, runId: number)` | `Promise` | Re-run a completed action run. | | `cancelAction` | `(ownerRepo: string, runId: number)` | `Promise` | Cancel an in-progress action run. | ### Parameter Conventions - **`ownerRepo`** -- Repository identifier in `"owner/repo"` format (e.g., `"my-org/my-repo"`). - **`orgName`** -- Organization login name (e.g., `"my-org"`). - **`key`** -- Secret name, typically uppercase with underscores (e.g., `"DEPLOY_TOKEN"`). - **`runId` / `jobId`** -- Numeric identifiers returned by the list endpoints. ## Interfaces All interfaces are exported from the package entry point and can be imported for type annotations. ```typescript import type { IGiteaUser, IGiteaRepository, IGiteaOrganization, IGiteaSecret, IGiteaActionRun, IGiteaActionRunJob, ITestConnectionResult, IListOptions, } from '@apiclient.xyz/gitea'; ``` ### `IListOptions` Pagination and search options accepted by list methods. ```typescript interface IListOptions { search?: string; // Free-text search query (repos only) page?: number; // Page number (default: 1) perPage?: number; // Results per page (default: 50 for repos/orgs, 30 for runs) } ``` ### `ITestConnectionResult` ```typescript interface ITestConnectionResult { ok: boolean; // true if the connection succeeded error?: string; // Error message when ok is false } ``` ### `IGiteaUser` ```typescript interface IGiteaUser { id: number; login: string; full_name: string; email: string; avatar_url: string; } ``` ### `IGiteaRepository` ```typescript interface IGiteaRepository { id: number; name: string; full_name: string; // "owner/repo" description: string; default_branch: string; html_url: string; private: boolean; topics: string[]; updated_at: string; // ISO 8601 timestamp owner: { id: number; login: string; avatar_url: string; }; } ``` ### `IGiteaOrganization` ```typescript interface IGiteaOrganization { id: number; name: string; full_name: string; description: string; visibility: string; // "public", "limited", or "private" repo_count: number; } ``` ### `IGiteaSecret` ```typescript interface IGiteaSecret { name: string; // Secret key name created_at: string; // ISO 8601 timestamp } ``` ### `IGiteaActionRun` ```typescript interface IGiteaActionRun { id: number; name: string; // Workflow name status: string; // "running", "waiting", "success", "failure", etc. conclusion: string; // Final result: "success", "failure", "cancelled", etc. head_branch: string; // Branch that triggered the run head_sha: string; // Commit SHA html_url: string; // Web URL for the run event: string; // Trigger event: "push", "pull_request", etc. run_duration: number; // Duration in seconds created_at: string; // ISO 8601 timestamp } ``` ### `IGiteaActionRunJob` ```typescript interface IGiteaActionRunJob { id: number; name: string; // Job name from the workflow status: string; conclusion: string; run_duration: number; // Duration in seconds } ``` ## License MIT -- see [LICENSE](./license.md) for details. Published under the [Lossless GmbH](https://lossless.com) umbrella.