import axios from "axios"; import type { IssueError, IssueLinkTypesPayload, YoutrackArticle, YoutrackConfig, YoutrackIssueDetails, YoutrackIssueLinkType, YoutrackProject, YoutrackProjectListPayload, YoutrackUser } from "../types.js"; export declare const DEFAULT_PAGE_SIZE = 200; export declare const DEFAULT_EXPECTED_MINUTES: number; export declare const MAX_STAR_BATCH_SIZE = 50; export declare const CUSTOM_FIELDS_STATE_FETCH = "id,name,value(id,name,presentation),$type,possibleEvents(id,presentation)"; export declare function withIssueCustomFieldEvents(baseFields: string): string; export declare function withIssueDetailsCustomFieldEvents(baseFields: string): string; export declare const defaultFields: { readonly issue: string; readonly issueSearch: string; readonly issueSearchBrief: string; readonly issueDetails: string; readonly issueDetailsLight: "id,idReadable,updated,updater(login)"; readonly comments: "id,text,textPreview,usesMarkdown,author(id,login,name),created,updated"; readonly commentsLight: "id,author(login),created,text"; readonly workItem: "id,date,updated,duration(minutes,presentation),text,textPreview,usesMarkdown,description,issue(id,idReadable),author(id,login,name,email)"; readonly workItems: "id,date,updated,duration(minutes,presentation),text,textPreview,usesMarkdown,description,issue(id,idReadable),author(id,login,name,email)"; readonly users: "id,login,name,fullName,email"; readonly projects: "id,shortName,name"; readonly article: "id,idReadable,summary,content,usesMarkdown,parentArticle(id,idReadable),project(id,shortName,name)"; readonly articleList: "id,idReadable,summary,parentArticle(id,idReadable),project(id,shortName,name)"; readonly attachment: "id,name,author(id,login,name),created,updated,size,mimeType,url,thumbnailURL,extension"; readonly attachments: "id,name,author(id,login,name),created,updated,size,mimeType,extension"; readonly issueLinks: "id,direction,linkType(id,name,directed,outwardName,inwardName),issues(idReadable,summary,project(id,shortName,name),assignee(id,login,name))"; readonly linkTypes: "id,name,directed,outwardName,inwardName,sourceToTarget,targetToSource"; }; /** * URL-encode a single path segment. Tool-level zod validators already restrict * id-like inputs to safe character sets; encoding here is defense-in-depth so * that any unexpected character cannot break out of the intended path. */ export declare function encId(value: string): string; /** * Generic constructor type used by domain mixins. The `any[]` is the standard * TypeScript mixin idiom: it allows the mixin to extend any subclass of the * given base regardless of its constructor signature. */ export type Constructor = new (...args: any[]) => T; export declare class YoutrackClientError extends Error { readonly status?: number | undefined; readonly details?: unknown; constructor(message: string, status?: number, details?: unknown); } /** * Base layer of the YoutrackClient: holds the axios instance, the per-process * caches (users / projects / link types) and the low-level helpers that domain * code reuses (`getWithFlexibleTop`, `processBatch`, `normalizeError`). * * Concrete `YoutrackClient` extends this base and adds domain methods * (issues, work items, articles, attachments, etc.). */ export declare class YoutrackClientBase { protected readonly config: YoutrackConfig; protected readonly http: ReturnType; protected cachedCurrentUser?: YoutrackUser; protected readonly usersByLogin: Map; protected readonly projectsByShortName: Map; protected readonly projectsById: Map; protected readonly defaultProject?: string | undefined; protected readonly linkTypesById: Map; protected readonly linkTypesByName: Map; protected cachedCommandSupport?: boolean | undefined; protected cachedCountSupport?: boolean | undefined; protected listProjectsInFlight?: Promise | undefined; protected listLinkTypesInFlight?: Promise | undefined; constructor(config: YoutrackConfig); /** * Returns the absolute output directory configured via YOUTRACK_OUTPUT_DIR. * All file-writing tools resolve relative paths against this root. */ getOutputDir(): string; /** * Returns the configured YouTrack base URL. Useful for building user-facing * deep links inside tools without poking into protected `config`. */ getBaseUrl(): string; /** * Public wrapper around the issue list endpoint with `$top`/`$skip` fallback. * Tools should call this instead of reaching into protected `getWithFlexibleTop`. */ searchIssues(params: { query?: string | undefined; fields?: string | undefined; $top?: number; $skip?: number; }): Promise; /** * Public wrapper around the articles list endpoint. Tools should call this * instead of reaching into protected `getWithFlexibleTop`. */ searchArticles(params: { query?: string | undefined; fields?: string | undefined; $top?: number; $skip?: number; }): Promise; /** * GET helper that prefers `$top`/`$skip` and retries with `top`/`skip` on 400. * Returns only `data` for convenience. */ protected getWithFlexibleTop(url: string, params: Record): Promise; /** * Process items with concurrency limit using MutexPool. Errors are collected * and rethrown after all jobs finish: a single error is rethrown directly, * multiple are wrapped into AggregateError. Callers that need soft semantics * must wrap their own processor in try/catch and return a per-item payload. */ protected processBatch(items: T[], processor: (item: T) => Promise, limit?: number): Promise; /** * Look up issues by id with a single `issue id: A B C` search, then re-check * the ids the search did not return. * * The search is not reliable on its own. As soon as one id cannot be resolved, * YouTrack answers 200 with an EMPTY list instead of the resolvable subset, * and when none of the ids resolve it answers 400 `invalid_query`. Treating * "absent from the response" as "does not exist" would therefore report * existing issues as missing whenever a dead id travels in the same batch. * * Ids are matched case-insensitively, because YouTrack returns the canonical * `idReadable` (`BC-1`) whatever case the caller used (`bc-1`). * * Cost: the common case (every id resolvable) is one request. A poisoned * search returns nothing, so every requested id is re-checked: one dead id in * a batch of N turns 1 request into N+1, at concurrency 10. */ protected findIssuesByIds(resolvedIds: string[], fields: string): Promise<{ issues: YoutrackIssueDetails[]; errors: IssueError[]; }>; /** * Resolve each id individually via `GET /api/issues/`. A 404 confirms the * id is really gone; any other failure (timeout, 5xx, 403 on a project the * token cannot read) is reported with its own message, not as "not found". */ private verifyMissingIssues; /** * Expand a bare numeric issue id to the project-prefixed form when * `defaultProject` is configured. "123" -> "PROJ-123". Strings that already * contain "-" are passed through. Used by every domain that accepts an * issueId from a tool call. */ protected resolveIssueId(rawIssueId: string): string; protected resolveIssueIds(issueIds: string[]): string[]; protected normalizeError(error: unknown): YoutrackClientError; } //# sourceMappingURL=base.d.ts.map