@openma/matter-gitlab 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,477 @@
1
+ import { BondBinding, BondManifest, BondProvider, BondResourceCatalog, ProviderError, SecretRef, TokenGrant } from "@openma/matter/bond";
2
+ import { Effect } from "effect";
3
+ import { JsonValue, WorkEvent } from "@openma/matter";
4
+ import { CredentialResolver } from "@openma/matter/credentials";
5
+ import { IntegrationError, WorkIntegration } from "@openma/matter/integration";
6
+ import { HttpEndpoint } from "@openma/matter/http";
7
+ //#region src/bond/http.d.ts
8
+ type Fetch = typeof globalThis.fetch;
9
+ /**
10
+ * Normalizes a GitLab instance URL to its canonical https origin. Rejects
11
+ * plain http except for loopback hosts, and rejects paths, credentials,
12
+ * queries, and fragments.
13
+ */
14
+ declare const canonicalOrigin: (input: string) => string;
15
+ //#endregion
16
+ //#region src/bond/oauth.d.ts
17
+ /**
18
+ * What discovery verified. OAuth calls always use the instance's fixed
19
+ * `/oauth/authorize`, `/oauth/token`, and `/oauth/revoke` under `origin`, so
20
+ * discovery returns no endpoints that callers might follow elsewhere.
21
+ */
22
+ interface GitLabInstance {
23
+ readonly origin: string;
24
+ /** Whether the instance enables the device authorization grant. */
25
+ readonly deviceFlow: boolean;
26
+ }
27
+ /**
28
+ * Reads OIDC discovery and requires authorization code with PKCE S256 and
29
+ * refresh tokens, and an issuer equal to the instance origin. Device flow is
30
+ * recorded when present; GitLab can disable it per instance.
31
+ */
32
+ declare const discoverInstance: (origin: string, fetchImpl?: Fetch) => Effect.Effect<GitLabInstance, ProviderError>;
33
+ interface Pkce {
34
+ readonly verifier: string;
35
+ readonly challenge: string;
36
+ readonly method: "S256";
37
+ }
38
+ /** A fresh PKCE verifier and its S256 challenge. Keep the verifier server-side. */
39
+ declare const createPkce: () => Effect.Effect<Pkce>;
40
+ interface AuthorizationUrlInput {
41
+ readonly origin: string;
42
+ readonly clientId: string;
43
+ readonly redirectUri: string;
44
+ readonly scopes: readonly string[];
45
+ /** Signed, single-use state bound to the user and ProviderApp. */
46
+ readonly state: string;
47
+ readonly codeChallenge: string;
48
+ }
49
+ declare const authorizationUrl: (input: AuthorizationUrlInput) => string;
50
+ interface OAuthClient {
51
+ readonly origin: string;
52
+ readonly clientId: string;
53
+ /** Absent for public clients. */
54
+ readonly clientSecret?: string;
55
+ readonly fetch?: Fetch;
56
+ /** ISO now, for computing expiry. */
57
+ readonly clock?: () => string;
58
+ }
59
+ /** Exchanges an authorization code. A wrong verifier does not consume the code on GitLab. */
60
+ declare const exchangeCode: (client: OAuthClient, input: {
61
+ readonly code: string;
62
+ readonly redirectUri: string;
63
+ readonly codeVerifier: string;
64
+ }) => Effect.Effect<TokenGrant, ProviderError, never>;
65
+ /**
66
+ * Refreshes a user token. GitLab rotates both tokens and invalidates the old
67
+ * access token immediately, and does not detect refresh-token reuse, so the
68
+ * caller must hold the Bond refresh lease.
69
+ */
70
+ declare const refreshAccessToken: (client: OAuthClient, refreshToken: string) => Effect.Effect<TokenGrant, ProviderError, never>;
71
+ /**
72
+ * Revokes one access or refresh token. GitLab (Doorkeeper) stores an access
73
+ * token and its refresh token as one record, so revoking either ends that
74
+ * pair only. Other tokens the same user holds for the same application keep
75
+ * working: on a live instance, revoking the previous token after a relink left
76
+ * the new one valid.
77
+ */
78
+ declare const revokeToken: (client: OAuthClient, token: string) => Effect.Effect<undefined, ProviderError, never>;
79
+ //#endregion
80
+ //#region src/bond/tokens.d.ts
81
+ /** `GET /api/v4/user`. Numeric `id` is the stable key; the rest is display data. */
82
+ interface GitLabUser {
83
+ readonly id: string;
84
+ readonly username: string;
85
+ readonly name: string;
86
+ readonly commitEmail?: string;
87
+ readonly bot: boolean;
88
+ readonly identities: readonly {
89
+ readonly provider: string;
90
+ readonly externUid: string;
91
+ }[];
92
+ }
93
+ /** `GET /api/v4/personal_access_tokens/self`. Works for personal, project, and group access tokens. */
94
+ interface GitLabTokenInfo {
95
+ readonly id: string;
96
+ readonly name: string;
97
+ readonly active: boolean;
98
+ readonly revoked: boolean;
99
+ readonly scopes: readonly string[];
100
+ /** `YYYY-MM-DD`, or undefined for a token without expiry. */
101
+ readonly expiresAt?: string;
102
+ readonly userId: string;
103
+ }
104
+ declare const readUser: (origin: string, token: string, fetchImpl?: Fetch) => Effect.Effect<GitLabUser, ProviderError>;
105
+ declare const readTokenInfo: (origin: string, token: string, fetchImpl?: Fetch) => Effect.Effect<GitLabTokenInfo, ProviderError>;
106
+ /** `DELETE /api/v4/personal_access_tokens/self`: a token revokes itself. */
107
+ declare const revokeSelfToken: (origin: string, token: string, fetchImpl?: Fetch) => Effect.Effect<void, ProviderError>;
108
+ interface TokenPolicy {
109
+ readonly allowedScopes: readonly string[];
110
+ readonly maxLifetimeDays: number;
111
+ /** ISO now. */
112
+ readonly now: string;
113
+ }
114
+ type TokenProblem = "inactive" | "revoked" | "no_expiry" | "expired" | "lifetime_exceeded" | "scope_not_allowed" | "not_a_bot" | "is_a_bot" | "user_mismatch";
115
+ /** End of the UTC expiry day, which is when GitLab stops accepting the token. */
116
+ declare const tokenExpiryInstant: (expiresAt: string) => string;
117
+ /**
118
+ * Checks a pasted personal access token: active, scopes within the allowed
119
+ * set, an expiry within the maximum lifetime, and a human owner.
120
+ */
121
+ declare const validatePersonalAccessToken: (info: GitLabTokenInfo, user: GitLabUser, policy: TokenPolicy) => readonly TokenProblem[];
122
+ /**
123
+ * Checks a bot credential registered as an Installation: the same token
124
+ * checks, plus `bot: true` on its user. A human account's token is never
125
+ * accepted as an app principal.
126
+ */
127
+ declare const validateBotCredential: (info: GitLabTokenInfo, user: GitLabUser, policy: TokenPolicy) => readonly TokenProblem[];
128
+ //#endregion
129
+ //#region src/bond/classify.d.ts
130
+ type GitLabOperation = "fetch" | "push" | "read" | "open_mr" | "comment_mr";
131
+ /**
132
+ * A normalized project reference. Paths are lower-cased and stripped of
133
+ * `.git`; numeric IDs stay numeric. Both forms name one project only after
134
+ * the application resolves them through GitLab.
135
+ */
136
+ type ProjectRef = {
137
+ readonly kind: "id";
138
+ readonly id: number;
139
+ } | {
140
+ readonly kind: "path";
141
+ readonly path: string;
142
+ };
143
+ type GitLabRequestClass = {
144
+ readonly allow: true;
145
+ readonly projectRef: ProjectRef;
146
+ readonly operation: GitLabOperation;
147
+ /** `git` for smart HTTP, `rest` for `/api/v4`. */
148
+ readonly surface: "git" | "rest";
149
+ /**
150
+ * For `rest`: the validated path after `/api/v4/projects/<ref>`, to
151
+ * append to the resolved numeric project ID. For `open_mr`, the proxy
152
+ * must also check the body with `mergeRequestBodyProblem`.
153
+ */
154
+ readonly restTail?: string;
155
+ } | {
156
+ readonly allow: false;
157
+ readonly reason: string;
158
+ };
159
+ /**
160
+ * Classifies one request in GitLab's own URL shape. Allows git smart HTTP
161
+ * fetch and push, REST reads of a project, merge request creation, and
162
+ * merge request notes. Denies GraphQL, LFS, archives, raw files, and every
163
+ * other route.
164
+ */
165
+ declare const classifyGitLabRequest: (method: string, url: string | URL) => GitLabRequestClass;
166
+ /**
167
+ * GitLab lets `POST /projects/:id/merge_requests` name another project in
168
+ * `target_project_id`, so the URL alone does not bound where the merge
169
+ * request opens. Returns the reason to deny, or undefined when the body
170
+ * targets the classified project.
171
+ *
172
+ * Pass the parsed JSON object or form body and the numeric ID the URL's
173
+ * project reference resolved to, then forward the body you checked
174
+ * (re-serialized), never the raw bytes: parsers disagree on repeated keys.
175
+ * For the same reason a form that repeats `target_project_id`, or uses a
176
+ * variant such as `target_project_id[]`, is denied.
177
+ */
178
+ declare const mergeRequestBodyProblem: (body: unknown, resolvedProjectId: number) => string | undefined;
179
+ //#endregion
180
+ //#region src/bond/receive-pack.d.ts
181
+ declare const ZERO_OID: string;
182
+ interface ReceivePackCommand {
183
+ readonly oldId: string;
184
+ readonly newId: string;
185
+ readonly ref: string;
186
+ }
187
+ interface ReceivePackHead {
188
+ readonly commands: readonly ReceivePackCommand[];
189
+ readonly capabilities: readonly string[];
190
+ readonly options: readonly string[];
191
+ /** Bytes consumed by the head. The pack starts here. */
192
+ readonly headLength: number;
193
+ }
194
+ type ReceivePackParse = {
195
+ readonly _tag: "Complete";
196
+ readonly head: ReceivePackHead;
197
+ } | {
198
+ readonly _tag: "Incomplete";
199
+ } | {
200
+ readonly _tag: "Malformed";
201
+ readonly reason: string;
202
+ };
203
+ /** Bounds on a hostile head. Exceeding one is Malformed, never Incomplete. */
204
+ interface ReceivePackLimits {
205
+ /** Default 1 MiB. */
206
+ readonly maxHeadBytes?: number;
207
+ /** Default 1000. */
208
+ readonly maxCommands?: number;
209
+ /** Default 100. */
210
+ readonly maxOptions?: number;
211
+ }
212
+ /**
213
+ * A strict subset of `git check-ref-format`: a full `refs/` name with no
214
+ * control characters, no characters git forbids, no empty, dot-leading, or
215
+ * `.lock` components, no `..`, and no `@{`.
216
+ */
217
+ declare const isValidRefName: (ref: string) => boolean;
218
+ interface ReceivePackHeadParser {
219
+ /** Feeds the next chunk of the request body. */
220
+ readonly push: (chunk: Uint8Array) => ReceivePackParse;
221
+ /**
222
+ * Bytes after the head in the chunk that completed it: the start of the
223
+ * pack. Later chunks are not buffered; stream them upstream directly.
224
+ */
225
+ readonly remainder: () => Uint8Array;
226
+ }
227
+ /**
228
+ * Incremental receive-pack head parser. Each byte is examined once, and only
229
+ * an unfinished pkt-line is buffered, so a head fed in many small chunks
230
+ * costs linear time. Capabilities are the union over every command line, as
231
+ * in git's `read_head`: a client cannot hide `push-options` behind a later
232
+ * line without them.
233
+ */
234
+ declare const makeReceivePackHeadParser: (limits?: ReceivePackLimits) => ReceivePackHeadParser;
235
+ /**
236
+ * Parses as much of the receive-pack head as `bytes` holds. A convenience
237
+ * for a buffered prefix; streaming proxies should use
238
+ * `makeReceivePackHeadParser` and feed chunks as they arrive.
239
+ */
240
+ declare const parseReceivePackHead: (bytes: Uint8Array, limits?: ReceivePackLimits) => ReceivePackParse;
241
+ interface PushPolicy {
242
+ /** The project's default branch name, refreshed from GitLab by project ID. */
243
+ readonly defaultBranch: string;
244
+ /** Allow pushing to the default branch. Default false. */
245
+ readonly allowDefaultBranch?: boolean;
246
+ /** Only branches with this prefix may be updated, when set. */
247
+ readonly branchPrefix?: string;
248
+ /** Label every merge request created by push option must carry. */
249
+ readonly requiredMergeRequestLabel: string;
250
+ /** Whether `merge_request.*` options are allowed at all (the `open_mr` grant). */
251
+ readonly allowMergeRequestOptions: boolean;
252
+ }
253
+ /**
254
+ * Returns the reason a push is denied, or undefined when it is allowed.
255
+ * Denies tags and other non-branch refs, deletions, the default branch, and
256
+ * any push option outside the merge request allow-list. GitLab still applies
257
+ * its own branch protection afterwards.
258
+ */
259
+ declare const evaluatePush: (head: ReceivePackHead, policy: PushPolicy) => string | undefined;
260
+ //#endregion
261
+ //#region src/bond/attribution.d.ts
262
+ interface CommitIdentity {
263
+ readonly name: string;
264
+ readonly email: string;
265
+ }
266
+ /** The commit author for a GitLab user: their name and `commit_email`. */
267
+ declare const commitAuthor: (user: {
268
+ readonly name: string;
269
+ readonly username: string;
270
+ readonly commitEmail?: string;
271
+ }) => CommitIdentity;
272
+ /** `Assisted-by: <app> <session URL>`, added to every commit. */
273
+ declare const assistedByTrailer: (appName: string, sessionUrl: string) => string;
274
+ /** `Co-authored-by` for a participant or, with the app principal, the requester. */
275
+ declare const coAuthoredByTrailer: (who: CommitIdentity) => string;
276
+ /** Description footer for merge requests and comments. */
277
+ declare const mergeRequestFooter: (input: {
278
+ readonly appName: string;
279
+ readonly sessionUrl: string;
280
+ /** Username of the requesting user; set when the app principal authors. */
281
+ readonly requestedBy?: string;
282
+ }) => string;
283
+ /** `git push -o` options that create a labelled merge request. */
284
+ declare const mergeRequestPushOptions: (input: {
285
+ readonly target: string;
286
+ readonly title: string;
287
+ readonly description: string;
288
+ readonly label: string;
289
+ }) => readonly string[];
290
+ //#endregion
291
+ //#region src/bond/provider.d.ts
292
+ interface GitLabBondProviderOptions {
293
+ readonly fetch?: Fetch;
294
+ readonly clock?: () => string;
295
+ /** Resolves `oauth.clientSecret` references. Omit for public clients. */
296
+ readonly resolveSecret?: (ref: SecretRef) => Effect.Effect<string, unknown>;
297
+ }
298
+ /**
299
+ * Bond's GitLab provider. A configured `oauth.clientSecret` requires
300
+ * `resolveSecret`; the provider never silently degrades to a public client. GitLab has no delegation marker, so user-principal
301
+ * writes need the ProviderApp's `allowUserPrincipalOutput`. The app principal
302
+ * is a registered bot credential stored on the Installation; GitLab 17.1
303
+ * cannot rotate it from the bot itself, so an administrator replaces it.
304
+ */
305
+ declare const makeGitLabBondProvider: (options?: GitLabBondProviderOptions) => BondProvider;
306
+ //#endregion
307
+ //#region src/bond/resources.d.ts
308
+ /** Minimum GitLab access level per operation: 20 Reporter, 30 Developer. */
309
+ declare const GITLAB_MIN_ACCESS_LEVEL: Readonly<Record<GitLabOperation, number>>;
310
+ declare const gitlabManifest: BondManifest;
311
+ interface GitLabResourceCatalogOptions {
312
+ readonly fetch?: Fetch;
313
+ }
314
+ /**
315
+ * Projects as Bond resources, with IDs `project:<numeric id>`. Paths are
316
+ * display data only. `list` returns projects where the token holds at least
317
+ * Reporter; `validate` checks the access level each operation needs and
318
+ * refuses writes to archived projects. An instance administrator without a
319
+ * membership reports no access level and is treated as having none.
320
+ */
321
+ declare const makeGitLabResourceCatalog: (options?: GitLabResourceCatalogOptions) => BondResourceCatalog;
322
+ /** The provider, manifest, and resource catalog a host registers for GitLab. */
323
+ declare const makeGitLabBinding: (options?: GitLabBondProviderOptions) => BondBinding;
324
+ //#endregion
325
+ //#region src/bond/integration/client.d.ts
326
+ /**
327
+ * What a GitLab call needs for one authority: the instance and a token with
328
+ * API access (a Bond's app principal token, or a test token).
329
+ */
330
+ interface GitLabCredentials {
331
+ /** The instance root, for example `https://gitlab.example.com`. */
332
+ readonly baseUrl: string;
333
+ readonly token: string;
334
+ }
335
+ type GitLabCredentialResolver = CredentialResolver<GitLabCredentials>;
336
+ type GitLabCredentialSource = (authority: string) => GitLabCredentials | PromiseLike<GitLabCredentials> | Effect.Effect<GitLabCredentials, unknown>;
337
+ type GitLabCredentialOption = GitLabCredentials | GitLabCredentialResolver | GitLabCredentialSource;
338
+ type GitLabCredentialsFor = (authority: string) => Effect.Effect<GitLabCredentials, IntegrationError>;
339
+ declare const makeGitLabCredentialsFor: (option: GitLabCredentialOption) => GitLabCredentialsFor;
340
+ interface GitLabResponse {
341
+ readonly payload: JsonValue;
342
+ readonly headers: Headers;
343
+ }
344
+ declare const makeGitLabClient: (input: {
345
+ readonly credentialsFor: GitLabCredentialsFor;
346
+ readonly fetch: typeof globalThis.fetch;
347
+ readonly clock: () => string;
348
+ }) => {
349
+ request: (options: {
350
+ readonly authority: string;
351
+ readonly method: "DELETE" | "GET" | "POST" | "PUT";
352
+ readonly path: string;
353
+ readonly body?: Readonly<Record<string, unknown>>;
354
+ }) => Effect.Effect<GitLabResponse, IntegrationError>;
355
+ };
356
+ type GitLabClient = ReturnType<typeof makeGitLabClient>;
357
+ //#endregion
358
+ //#region src/bond/integration/delivery.d.ts
359
+ /** Every Effect operation `deliver` accepts. */
360
+ declare const GITLAB_OPERATIONS: readonly ["merge_request.note.create", "merge_request.discussion.reply", "issue.note.create", "issue.discussion.reply"];
361
+ type GitLabEffectOperation = (typeof GITLAB_OPERATIONS)[number];
362
+ /**
363
+ * Delivers GitLab Effects. Every input names the `authority` whose
364
+ * credentials post the note, the `projectId` (numeric id or full path), the
365
+ * merge request or issue `iid`, and a non-empty `body`. Discussion replies
366
+ * also name the `discussionId`; replying to a single comment turns it into a
367
+ * thread.
368
+ */
369
+ declare const makeGitLabDelivery: (client: Pick<GitLabClient, "request">) => WorkIntegration["deliver"];
370
+ //#endregion
371
+ //#region src/bond/integration/events.d.ts
372
+ /** Every Event type `ingest` can produce. */
373
+ declare const GITLAB_EVENT_TYPES: readonly string[];
374
+ /**
375
+ * Turns a verified `GitLabWebhookInput` into one WorkEvent. Inputs of another
376
+ * kind produce no Events. The Event id combines the authority and the
377
+ * delivery id, so a GitLab retry is the same Event.
378
+ */
379
+ declare const normalizeGitLabEvents: (input: unknown, clock: () => string) => Effect.Effect<readonly WorkEvent[], IntegrationError>;
380
+ //#endregion
381
+ //#region src/bond/integration/http.d.ts
382
+ declare const GitLabHttpIngressError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
383
+ readonly _tag: "GitLabHttpIngressError";
384
+ } & Readonly<A>;
385
+ declare class GitLabHttpIngressError extends GitLabHttpIngressError_base<{
386
+ readonly message: string;
387
+ readonly status: 400 | 401;
388
+ readonly cause?: unknown;
389
+ }> {}
390
+ declare const GitLabHttpSubmissionError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
391
+ readonly _tag: "GitLabHttpSubmissionError";
392
+ } & Readonly<A>;
393
+ declare class GitLabHttpSubmissionError extends GitLabHttpSubmissionError_base<{
394
+ readonly message: string;
395
+ readonly status: 503;
396
+ readonly cause?: unknown;
397
+ }> {}
398
+ /** One verified GitLab webhook delivery, ready for `integration.ingest`. */
399
+ interface GitLabWebhookInput {
400
+ readonly kind: "gitlab.webhook";
401
+ /**
402
+ * Who received the webhook, chosen by the host (for example a Bond id).
403
+ * It becomes the Event source authority and selects credentials for replies.
404
+ */
405
+ readonly authority: string;
406
+ /** The `X-Gitlab-Event` header, for example `Merge Request Hook`. */
407
+ readonly eventName: string;
408
+ /** Stable across GitLab retries; see `decodeGitLabHttpRequest`. */
409
+ readonly deliveryId: string;
410
+ /** The `X-Gitlab-Instance` header (GitLab 15.5+), when present. */
411
+ readonly instance?: string;
412
+ readonly payload: JsonValue;
413
+ }
414
+ interface GitLabHttpEndpointOptions {
415
+ /** The secret token configured on the GitLab webhook. */
416
+ readonly webhookToken: string;
417
+ readonly authority: string;
418
+ readonly path?: string;
419
+ readonly submit: (input: GitLabWebhookInput) => Promise<unknown>;
420
+ }
421
+ /**
422
+ * Compares the `X-Gitlab-Token` header with the configured secret token in
423
+ * constant time. Both values are hashed first, so the comparison does not
424
+ * reveal the secret's length either. An empty configured token never matches.
425
+ */
426
+ declare const verifyGitLabToken: (input: {
427
+ readonly webhookToken: string;
428
+ readonly received: string;
429
+ }) => Effect.Effect<boolean, GitLabHttpIngressError>;
430
+ /**
431
+ * Verifies and decodes one GitLab webhook request. The delivery id is the
432
+ * first of `webhook-id` and `Idempotency-Key` (both stable across retries,
433
+ * GitLab 17.4+) and `X-Gitlab-Event-UUID` (GitLab 14.8+).
434
+ */
435
+ declare const decodeGitLabHttpRequest: (request: Request, options: Pick<GitLabHttpEndpointOptions, "webhookToken" | "authority">) => Effect.Effect<GitLabWebhookInput, GitLabHttpIngressError>;
436
+ /**
437
+ * A webhook endpoint for one GitLab authority. Hosts that serve many
438
+ * authorities from one route call `decodeGitLabHttpRequest` with the token
439
+ * and authority they look up for the request instead.
440
+ */
441
+ declare const makeGitLabHttpEndpoint: (options: GitLabHttpEndpointOptions) => HttpEndpoint;
442
+ //#endregion
443
+ //#region src/bond/integration/integration.d.ts
444
+ interface GitLabIntegrationOptions {
445
+ /**
446
+ * Credentials for replies: fixed `{ baseUrl, token }`, or a resolver keyed
447
+ * by the Event authority (for example a Bond's app principal).
448
+ */
449
+ readonly credentials: GitLabCredentialOption;
450
+ readonly fetch?: typeof globalThis.fetch;
451
+ readonly clock?: () => string;
452
+ }
453
+ /**
454
+ * The GitLab work integration: `ingest` takes a `GitLabWebhookInput` from
455
+ * `decodeGitLabHttpRequest`, and `deliver` posts merge request and issue
456
+ * notes.
457
+ */
458
+ declare const makeGitLabIntegration: (options: GitLabIntegrationOptions) => WorkIntegration;
459
+ //#endregion
460
+ //#region src/bond/integration/templates.d.ts
461
+ /**
462
+ * Reviews a merge request when it opens, reopens, or receives new commits,
463
+ * and posts the review as a note. Title or label edits do not trigger a
464
+ * review. Draft merge requests are skipped unless `skipDrafts` is false.
465
+ */
466
+ declare const gitlabMergeRequestReview: import("@openma/matter-loop").Loop;
467
+ /**
468
+ * Answers a merge request comment that mentions the Agent's GitLab user, in
469
+ * the same thread. System notes and the Agent's own notes are ignored, so a
470
+ * reply never triggers another reply.
471
+ */
472
+ declare const gitlabMention: import("@openma/matter-loop").Loop;
473
+ /** The GitLab templates, in the order a console lists them. */
474
+ declare const gitlabTemplates: readonly [import("@openma/matter-loop").Loop, import("@openma/matter-loop").Loop];
475
+ //#endregion
476
+ export { type AuthorizationUrlInput, type CommitIdentity, type Fetch, GITLAB_EVENT_TYPES, GITLAB_MIN_ACCESS_LEVEL, GITLAB_OPERATIONS, type GitLabBondProviderOptions, type GitLabClient, type GitLabCredentialOption, type GitLabCredentialResolver, type GitLabCredentialSource, type GitLabCredentials, type GitLabEffectOperation, type GitLabHttpEndpointOptions, GitLabHttpIngressError, GitLabHttpSubmissionError, type GitLabInstance, type GitLabIntegrationOptions, type GitLabOperation, type GitLabRequestClass, type GitLabResourceCatalogOptions, type GitLabTokenInfo, type GitLabUser, type GitLabWebhookInput, type OAuthClient, type Pkce, type ProjectRef, type PushPolicy, type ReceivePackCommand, type ReceivePackHead, type ReceivePackHeadParser, type ReceivePackLimits, type ReceivePackParse, type TokenPolicy, type TokenProblem, ZERO_OID, assistedByTrailer, authorizationUrl, canonicalOrigin, classifyGitLabRequest, coAuthoredByTrailer, commitAuthor, createPkce, decodeGitLabHttpRequest, discoverInstance, evaluatePush, exchangeCode, gitlabManifest, gitlabMention, gitlabMergeRequestReview, gitlabTemplates, isValidRefName, makeGitLabBinding, makeGitLabBondProvider, makeGitLabClient, makeGitLabCredentialsFor, makeGitLabDelivery, makeGitLabHttpEndpoint, makeGitLabIntegration, makeGitLabResourceCatalog, makeReceivePackHeadParser, mergeRequestBodyProblem, mergeRequestFooter, mergeRequestPushOptions, normalizeGitLabEvents, parseReceivePackHead, readTokenInfo, readUser, refreshAccessToken, revokeSelfToken, revokeToken, tokenExpiryInstant, validateBotCredential, validatePersonalAccessToken, verifyGitLabToken };
477
+ //# sourceMappingURL=index.d.ts.map