返回资讯中心
外部精选
软件工程
#开发者实时流

Unified interface for issues, pull requests, notifications, checks and webhooks

A unified interface for issues, pull requests, notifications, checks and webhooks across 12 forgesA service that hosts Git repositories and the collaboration around them: issues, pull requests, reviews and CI. GitHub, G…

Hacker News 最新rmason2026/10/22 · 23 天前30 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

A unified interface for issues, pull requests, notifications, checks and webhooks across 12 forgesA service that hosts Git repositories and the collaboration around them: issues, pull requests, reviews and CI. GitHub, GitLab and Codeberg are forges..

import { function createForges<const T extends readonly ForgeProvider[]>(providers: T): Forges<RegisteredKinds<T>>Combines providers into a registry.

@paramproviders Providers such as github() creates.@example```ts import { createForges, github, gitlab, UnknownForgeError } from 'forges'

const forges = createForges([ github({ auth: { type: 'token', token: process.env.GITHUB_TOKEN! } }), gitlab(), ])

const ref = { forge: 'github', instance: 'github.com', owner: 'danielroe', name: 'forges' } as const const provider = forges.for(ref) if (!provider) { throw new UnknownForgeError(No provider registered for ${ref.forge} on ${ref.instance}, ref) } const repo = await provider.repos.get(ref)


createForges, const github: (options?: GitHubOptions | undefined) => GitHubProvider &#x26; {
 readonly forge: "github";
}

Creates a GitHub provider for github.com or a GitHub Enterprise Server instance.

github, const gitlab: (options?: GitLabOptions | undefined) => ForgeProvider&#x3C;true> &#x26; {
 readonly forge: "gitlab";
}

Creates a GitLab provider for gitlab.com or a self-managed instance.

gitlab } from 'forges'

const const forges: Forges&#x3C;"github" | "gitlab">

interface Forges {
 providers: ForgeProvider&#x3C;boolean>[]
 get: { (forge: "github" | "gitlab"): ForgeProvider&#x3C;boolean>; (forge: ForgeKind, instance?: string | undefined): ForgeProvider&#x3C;boolean> | undefined; }
 all: (forge: ForgeKind) => ForgeProvider&#x3C;boolean>[]
 for: (ref: ForgeOrigin) => ForgeProvider&#x3C;boolean> | undefined
 forUrl: (url: string | URL) => ForgeProvider&#x3C;boolean> | undefined
 parseUrl: (url: string | URL) => (ParsedForgeUrl &#x26; { provider: ForgeProvider&#x3C;boolean>; }) | undefined
 parseReferences: (text: string, options: ParseReferencesOptions) => ParsedReference[]
 notifications: { list: (options?: Omit&#x3C;NotificationListOptions, "cursor"> | undefined) => ForgeIterable&#x3C;Notification>; }
 threads: { getMany: (refs: ThreadRef[], options?: BaseOptions | undefined) => Promise&#x3C;GetManyResult[]>; }
 search: { threads: (query?: (Omit&#x3C;ThreadSearchQuery, "cursor" | "sort"> &#x26; { sort?: "created" | "updated" | undefined; }) | undefined) => ForgeIterable&#x3C;Thread>; repos: (query?: (Omit&#x3C;...> &#x26; { ...; }) | undefined) => ForgeIterable&#x3C;...>; }
}

forges = createForges&#x3C;readonly [GitHubProvider &#x26; {
 readonly forge: "github";
}, ForgeProvider&#x3C;true> &#x26; {
 readonly forge: "gitlab";
}]>(providers: readonly [GitHubProvider &#x26; {
 readonly forge: "github";
}, ForgeProvider&#x3C;true> &#x26; {
 readonly forge: "gitlab";
}]): Forges&#x3C;"github" | "gitlab">

Combines providers into a registry.

@paramproviders Providers such as `github()` creates.@example```ts
import { createForges, github, gitlab, UnknownForgeError } from 'forges'

const forges = createForges([
 github({ auth: { type: 'token', token: process.env.GITHUB_TOKEN! } }),
 gitlab(),
])

const ref = { forge: 'github', instance: 'github.com', owner: 'danielroe', name: 'forges' } as const
const provider = forges.for(ref)
if (!provider) {
 throw new UnknownForgeError(`No provider registered for ${ref.forge} on ${ref.instance}`, ref)
}
const repo = await provider.repos.get(ref)

createForges([ function github(options?: GitHubOptions | undefined): GitHubProvider & { readonly forge: "github"; }

Creates a GitHub provider for github.com or a GitHub Enterprise Server instance.

github({ GitHubOptions.auth?: GitHubAuth | undefinedHow to authenticate. Without credentials, only public reads work.

@default{ type: 'anonymous' }

auth: { TokenAuth.type: "token"type: 'token', TokenAuth.token: string | (() => string | Promise<string>)Personal access token or OAuth access token. A function is called before every request, so a refreshed token applies without a new provider.

token: var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnvThe process.env property returns an object containing the user environment. See environ(7).

@sincev0.1.27

env.string | undefinedGITHUB_TOKEN! } }), function gitlab(options?: GitLabOptions | undefined): ForgeProvider<true> & { readonly forge: "gitlab"; }

Creates a GitLab provider for gitlab.com or a self-managed instance.

gitlab({ GitLabOptions.auth?: GitLabAuth | undefinedHow to authenticate. Without credentials, only public reads work.

@default{ type: 'anonymous' }

auth: { TokenAuth.type: "token"type: 'token', TokenAuth.token: string | (() => string | Promise<string>)Personal access token or OAuth access token. A function is called before every request, so a refreshed token applies without a new provider.

token: var process: NodeJS.Processprocess.NodeJS.Process.env: NodeJS.ProcessEnvThe process.env property returns an object containing the user environment. See environ(7).

@sincev0.1.27

env.string | undefinedGITLAB_TOKEN! } }), ])

for await (const const notification: Notification

interface Notification { ref: NotificationRef subject: NotificationSubject reason: NotificationReason reasonRaw?: string | undefined subjectTypeRaw?: string | undefined unread: boolean title: string subjectState: ThreadState subjectStateRaw?: string | undefined updatedAt: Date lastReadAt?: Date | undefined url?: string | undefined latestComment?: ResolvedCommentRef | CommitCommentRef | undefined raw: unknown }

notification of const forges: Forges<"github" | "gitlab">

interface Forges { providers: ForgeProvider<boolean>[] get: { (forge: "github" | "gitlab"): ForgeProvider<boolean>; (forge: ForgeKind, instance?: string | undefined): ForgeProvider<boolean> | undefined; } all: (forge: ForgeKind) => ForgeProvider<boolean>[] for: (ref: ForgeOrigin) => ForgeProvider<boolean> | undefined forUrl: (url: string | URL) => ForgeProvider<boolean> | undefined parseUrl: (url: string | URL) => (ParsedForgeUrl & { provider: ForgeProvider<boolean>; }) | undefined parseReferences: (text: string, options: ParseReferencesOptions) => ParsedReference[] notifications: { list: (options?: Omit<NotificationListOptions, "cursor"> | undefined) => ForgeIterable<Notification>; } threads: { getMany: (refs: ThreadRef[], options?: BaseOptions | undefined) => Promise<GetManyResult[]>; } search: { threads: (query?: (Omit<ThreadSearchQuery, "cursor" | "sort"> & { sort?: "created" | "updated" | undefined; }) | undefined) => ForgeIterable<Thread>; repos: (query?: (Omit<...> & { ...; }) | undefined) => ForgeIterable<...>; } }

forges.Forges<"github" | "gitlab">.notifications: { list: (options?: Omit<NotificationListOptions, "cursor">) => ForgeIterable<Notification>; }

Notifications from every registered provider, provider by provider.

notifications.list: (options?: Omit<NotificationListOptions, "cursor">) => ForgeIterable<Notification>Lists the notifications of every provider, provider by provider.

list()) { var console: ConsoleThe console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

@seesource

console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

@sincev0.1.100

log(const notification: Notification

interface Notification { ref: NotificationRef subject: NotificationSubject reason: NotificationReason reasonRaw?: string | undefined subjectTypeRaw?: string | undefined unread: boolean title: string subjectState: ThreadState subjectStateRaw?: string | undefined updatedAt: Date lastReadAt?: Date | undefined url?: string | undefined latestComment?: ResolvedCommentRef | CommitCommentRef | undefined raw: unknown }

notification.Notification.ref: NotificationRef

interface NotificationRef { id: string forge: ForgeKind instance: string }

ref.ForgeOrigin.forge: ForgeKindforge, const notification: Notification

interface Notification { ref: NotificationRef subject: NotificationSubject reason: NotificationReason reasonRaw?: string | undefined subjectTypeRaw?: string | undefined unread: boolean title: string subjectState: ThreadState subjectStateRaw?: string | undefined updatedAt: Date lastReadAt?: Date | undefined url?: string | undefined latestComment?: ResolvedCommentRef | CommitCommentRef | undefined raw: unknown }

notification.Notification.title: stringtitle) }

features

You write your code against one model, and forges takes care of the endpoints, pagination, authentication and rate limits of each forge.

one data model

Issues, pull requests, comments, checks and events have the same shape on every forge, and the original payload is still there in the raw field when you need it.

declared capabilities

Every provider declares what its forge supports, and we check those claims against the tests on every commit to forges. Ask provider.can() before you call an operation.

verified webhooks

The provider verifies each delivery for you and turns it into typed events, with the same kinds and actions on every forge.

small bundles

Bundles keep only the forges you import, and the code that translates webhook deliveries loads only when you ingest one. The GitHub provider is about 38 kB gzipped.

offline tests

Test your code against an in-memory forge or replayed responses, without ever touching the network.

typed errors and retries

Rate limits, revoked tokens and missing scopes each have their own error class, and after a short rate limit the provider retries once by itself.

see what each forge can do

Every provider declares what its forge supports, so your code can check before it makes a call.

Support for selected capabilities, by forge CapabilityGitHubGitLabBitbucketForgejoGiteaGiteeAzure DevOpsCursor OriginPushin.euTangledCloudflare ArtifactsSourcehutthreads.mergeNativeNativeNativeNativeNativeNativeNativeExperimentalNot applicableNativeNot availableNot availablenotifications.listNativeNativeNot applicableNativeNativeNativeNot availableNot applicableNativeExperimentalNot availableNot availablechecks.listNativeNativeNativeNativeNativeNativeNativeUnverifiedNot availableNot applicableNot availableNot availableci.runsNativeNativeNot availableNativeNativeNot availableNot availableNot availableNot availableNot availableNot availableEmulatedreleases.listNativeNativeNot applicableNativeNativeNativeNot availableNot applicableNativeNot applicableNot availableEmulatedwebhooks.createNativeNativeNativeNativeNativeUnverifiedNot availableNot availableNot applicableNot applicableNot availableNot availablesearch.threadsNativeNativeNativeNativeNativeNativeNativeNot availableNot availableNot availableNot availableNot available

Native and verified

Experimental

Emulated

Unverified

Not applicable

Not available

read the full matrix

what you can build

Explore the examples and guides to get started on your next project.

a notification inbox

Merge the notifications of every forge you configure into one list.

a label bot

Label new threads, and close them from a comment command, on any forge.

a release digest

Show the latest release and the failing pull requests across repositories.

a webhook receiver

Turn the deliveries of any forge into a single event type.

make your first call

Install the package, read an issue and add a second forge.

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →