/** * daemon/forge-issues.ts — the issue tracker, for a session that receives from it. * * A sibling project already had all of this as a repo-local script whose token * lives in that repository's git config. It works, and it is the right shape * for a session working inside one checkout. It cannot help a session that * receives events for a tracker it has no clone of, which is the case this * exists for: the permission travels with the SUBSCRIPTION rather than with a * checkout, so a session may act on a tracker precisely when it is the one * being told about it. * * Three things are taken from that script deliberately rather than reinvented, * because each was learned the expensive way: * * **Every write reads itself back.** A network call returns and carries on. A * post that failed while the caller believed it succeeded is invisible until * somebody needs what it said — the same fault as a check that passes having * measured nothing, in its costliest form, because what is missing is a record * being relied upon. * * **404 is ambiguous and must be said so.** A forge answers 404 both for an * issue that does not exist and for one the credential cannot see. Reporting * the first when it is the second sends a reader looking for a missing thing * that is merely locked; twenty minutes went that way in one afternoon. * * **Closing is custody, not capability.** Receiving events about a tracker is * not owning what is in it. Closing is therefore restricted to issues this * account opened; anything else can be reported as fixed and left for a person. */ import { type RepoRef } from "./subscribe-issues.js"; /** Read-only verbs — safe to run against anything the subscription covers. */ export type ReadVerb = "get" | "comments" | "list" | "labels" | "assets"; /** Verbs that change the tracker. */ export type WriteVerb = "new" | "comment" | "amend" | "rewrite" | "retitle" | "label" | "unlabel" | "claim" | "release" | "close"; export type IssueVerb = ReadVerb | WriteVerb; export declare const READ_VERBS: ReadVerb[]; export declare const WRITE_VERBS: WriteVerb[]; /** The API root for a repository, on either forge shape. */ export declare function apiRoot(ref: RepoRef): string; /** * What a status code means here, in words a reader can act on. * * 404 gets the ambiguity spelled out because the two causes need opposite * responses: one is "the number is wrong", the other is "the token cannot see * this", and a bare "Not Found" reads as the first every time. */ export declare function explain(status: number): string; export interface IssueResult { ok: boolean; /** What the server holds, read back after a write rather than echoed. */ data?: unknown; /** The address of what was written, for a report that must carry a link. */ url?: string; error?: string; /** Set when the write landed but could not be confirmed. */ warning?: string; /** * Which issue this touched, when the caller did not name one. * * `amend` is given a COMMENT id, so the daemon cannot know from the request * which issue was written to — and what it cannot name, it cannot remember, * so the echo of an edit came straight back to its own session. The forge * says which issue a comment belongs to; this carries that answer back. */ issue?: number; } export interface Ctx { ref: RepoRef; token: string; fetchImpl: typeof fetch; /** The account the session posts as, for custody checks. */ botLogin?: string; /** Who to name in the signature on written text. The session, not the account. */ authorLabel?: string; } /** * The Authorization header. * * Two credential shapes are in use and both must work. An API token goes as * `token `. A user and password pair goes as Basic — which is what the * sibling project's script uses, and what somebody arriving from it will have. * Written as `user:secret` when it contains a colon, so one setting covers both * without a second variable to forget. */ export declare function authHeader(credential: string): string; export declare function whoAmI(c: Ctx): Promise; /** Forget cached identities. For tests, and for a rotated credential. */ export declare function forgetIdentities(): void; export declare function signature(author: string): string; /** The session named in a body’s trailing signature, if it carries one. */ export declare function signedAuthor(body: string): string | undefined; /** The issue number inside a comment’s issue_url, if the forge gave one. */ export declare function issueOfComment(c: { issue_url?: string; }): number | undefined; /** Strip a signature this wrote earlier, so rewrites do not accumulate them. */ export declare function unsign(body: string): string; /** * The body as it should be stored: the author's text, then the signature. * * Signing happens AFTER the emptiness check upstream, deliberately. A body that * is only a signature is an empty comment wearing a hat, and refusing it is the * point of that check. */ export declare function sign(body: string, author: string | undefined): string; /** * Run one verb. * * Every write path ends by reading the thing back and returning what the server * holds. Where the read-back fails, the result says the write is UNCONFIRMED * rather than reporting plain success — an unverified write reported as done is * the failure this whole module is shaped around. */ export declare function issueOp(verb: IssueVerb, args: { issue?: number; comment?: number; body?: string; title?: string; label?: string; state?: string; count?: number; }, ctx: { ref: RepoRef; token?: string; botLogin?: string; authorLabel?: string; fetchImpl?: typeof fetch; }): Promise; //# sourceMappingURL=forge-issues.d.ts.map