@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.
- package/LICENSE +202 -0
- package/README.md +10 -2
- package/dist/bond/index.d.ts +477 -0
- package/dist/bond/index.js +1541 -0
- package/dist/bond/index.js.map +1 -0
- package/package.json +30 -3
|
@@ -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
|