@alpacakit/integrations 0.1.0-beta.31 → 0.1.0-beta.36
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/README.md +6 -2
- package/dist/auth.d.ts +2 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +9 -1
- package/dist/catalog.d.ts +3 -3
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +10 -3
- package/dist/code-hosts/facets.d.ts +2 -2
- package/dist/code-hosts/facets.d.ts.map +1 -1
- package/dist/code-hosts/facets.js +4 -48
- package/dist/code-hosts/gitea-pull-request-snapshot.js +0 -1
- package/dist/code-hosts/gitea.d.ts.map +1 -1
- package/dist/code-hosts/gitea.js +100 -12
- package/dist/code-hosts/github.d.ts.map +1 -1
- package/dist/code-hosts/github.js +71 -21
- package/dist/code-hosts/gitlab.d.ts.map +1 -1
- package/dist/code-hosts/gitlab.js +70 -18
- package/dist/code-hosts/helpers.d.ts +12 -3
- package/dist/code-hosts/helpers.d.ts.map +1 -1
- package/dist/code-hosts/helpers.js +67 -7
- package/dist/code-hosts/repository-host.d.ts +4 -0
- package/dist/code-hosts/repository-host.d.ts.map +1 -0
- package/dist/code-hosts/repository-host.js +61 -0
- package/dist/code-hosts/repository-info.d.ts +4 -0
- package/dist/code-hosts/repository-info.d.ts.map +1 -0
- package/dist/code-hosts/repository-info.js +11 -0
- package/dist/code-hosts/strategy.d.ts +3 -2
- package/dist/code-hosts/strategy.d.ts.map +1 -1
- package/dist/definition.d.ts +18 -3
- package/dist/definition.d.ts.map +1 -1
- package/dist/definition.js +5 -0
- package/dist/error.d.ts +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/model.d.ts +10 -8
- package/dist/model.d.ts.map +1 -1
- package/dist/runtime.d.ts +12 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +25 -4
- package/dist/testing/contracts.d.ts +13 -2
- package/dist/testing/contracts.d.ts.map +1 -1
- package/dist/testing/contracts.js +108 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/transport/http-transport.js +1 -1
- package/dist/values.d.ts +13 -2
- package/dist/values.d.ts.map +1 -1
- package/dist/values.js +13 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,8 +7,12 @@ keyring support, and test fakes are isolated under subpath exports.
|
|
|
7
7
|
|
|
8
8
|
Repository setup is split into two provider-owned contracts:
|
|
9
9
|
`RepositoryScopeAdapter` applies provider-neutral repository updates to typed
|
|
10
|
-
connection settings and projects them back to
|
|
11
|
-
the
|
|
10
|
+
connection settings and projects them back to one `RepositoryScope` containing
|
|
11
|
+
the repository reference and canonical provider base URL, while the
|
|
12
|
+
connection-level `RepositoryHost` finds repositories or exclusively creates a
|
|
13
|
+
new private repository without adopting a name conflict. Repository facts
|
|
14
|
+
include the provider's opaque immutable repository ID alongside the canonical
|
|
15
|
+
reference and URL.
|
|
12
16
|
Repository-scoped issue, pull-request, and file operations remain on
|
|
13
17
|
`Repository`.
|
|
14
18
|
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { SecretRef, ValueOf } from "@alpacakit/core";
|
|
2
2
|
import type { IntegrationAuthProfileId, IntegrationId } from "./ids.js";
|
|
3
3
|
import type { SecretResolvers, SessionPorts } from "./ports.js";
|
|
4
|
-
import
|
|
5
|
-
import { AUTHORIZATION_KIND, INTEGRATION_AUTH_MATERIAL_KIND } from "./values.js";
|
|
4
|
+
import { AUTHORIZATION_KIND, INTEGRATION_AUTH_BINDING_KIND, INTEGRATION_AUTH_MATERIAL_KIND } from "./values.js";
|
|
6
5
|
export type { SecretRef } from "@alpacakit/core";
|
|
7
6
|
export type IntegrationAuthMaterial = {
|
|
8
7
|
readonly kind: typeof INTEGRATION_AUTH_MATERIAL_KIND.apiKey;
|
|
@@ -31,6 +30,7 @@ export type IntegrationAuthBinding = {
|
|
|
31
30
|
} | {
|
|
32
31
|
readonly kind: typeof INTEGRATION_AUTH_BINDING_KIND.anonymous;
|
|
33
32
|
};
|
|
33
|
+
export declare function sameIntegrationAuthBinding(left: IntegrationAuthBinding, right: IntegrationAuthBinding): boolean;
|
|
34
34
|
export type IntegrationAuthProfile = {
|
|
35
35
|
readonly id: IntegrationAuthProfileId;
|
|
36
36
|
readonly integrationId: IntegrationId;
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAM1D,OAAO,KAAK,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { AUTH_FAILURE_REASON, INTEGRATION_ERROR_CODE, IntegrationError, } from "./error.js";
|
|
2
|
-
import { AUTHORIZATION_KIND, AUTHORIZATION_SCHEME, INTEGRATION_AUTH_MATERIAL_KIND, } from "./values.js";
|
|
2
|
+
import { AUTHORIZATION_KIND, AUTHORIZATION_SCHEME, INTEGRATION_AUTH_BINDING_KIND, INTEGRATION_AUTH_MATERIAL_KIND, } from "./values.js";
|
|
3
3
|
const UTF8_ENCODING = "utf8";
|
|
4
4
|
const BASE64_ENCODING = "base64";
|
|
5
|
+
export function sameIntegrationAuthBinding(left, right) {
|
|
6
|
+
if (left.kind !== right.kind)
|
|
7
|
+
return false;
|
|
8
|
+
return left.kind !== INTEGRATION_AUTH_BINDING_KIND.profile
|
|
9
|
+
? true
|
|
10
|
+
: right.kind === INTEGRATION_AUTH_BINDING_KIND.profile &&
|
|
11
|
+
left.profileId === right.profileId;
|
|
12
|
+
}
|
|
5
13
|
export async function requireSecret(resolvers, ref) {
|
|
6
14
|
const resolver = resolvers[ref.resolver];
|
|
7
15
|
if (resolver === undefined) {
|
package/dist/catalog.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type JsonObject } from "@alpacakit/core";
|
|
2
|
-
import type { IntegrationDefinition, IntegrationSettingsInput } from "./definition.js";
|
|
2
|
+
import type { IntegrationDefinition, IntegrationSettingsInput, RepositoryRemoteResolution, RepositoryScope } from "./definition.js";
|
|
3
3
|
import type { IntegrationId } from "./ids.js";
|
|
4
|
-
import type { RepositoryRef } from "./model.js";
|
|
5
4
|
type AnyDefinition = IntegrationDefinition<IntegrationId, any, any>;
|
|
6
5
|
export interface IntegrationDefinitionCatalog {
|
|
7
6
|
resolveSettings(integration: IntegrationId, current: JsonObject | null, input: IntegrationSettingsInput): JsonObject;
|
|
8
|
-
|
|
7
|
+
projectRepositoryScope(integration: IntegrationId, settings: JsonObject): RepositoryScope;
|
|
8
|
+
resolveRepositoryRemote(integration: IntegrationId, remoteUrl: string): RepositoryRemoteResolution;
|
|
9
9
|
}
|
|
10
10
|
export declare function createIntegrationDefinitionCatalog(definitions: readonly AnyDefinition[]): IntegrationDefinitionCatalog;
|
|
11
11
|
export {};
|
package/dist/catalog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,0BAA0B,EAC1B,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQ9C,KAAK,aAAa,GAAG,qBAAqB,CAAC,aAAa,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEpE,MAAM,WAAW,4BAA4B;IAC3C,eAAe,CACb,WAAW,EAAE,aAAa,EAC1B,OAAO,EAAE,UAAU,GAAG,IAAI,EAC1B,KAAK,EAAE,wBAAwB,GAC9B,UAAU,CAAC;IACd,sBAAsB,CACpB,WAAW,EAAE,aAAa,EAC1B,QAAQ,EAAE,UAAU,GACnB,eAAe,CAAC;IACnB,uBAAuB,CACrB,WAAW,EAAE,aAAa,EAC1B,SAAS,EAAE,MAAM,GAChB,0BAA0B,CAAC;CAC/B;AAED,wBAAgB,kCAAkC,CAChD,WAAW,EAAE,SAAS,aAAa,EAAE,GACpC,4BAA4B,CAE9B"}
|
package/dist/catalog.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CODEC_DECODE_RESULT_KIND } from "@alpacakit/core";
|
|
2
2
|
import { INTEGRATION_ERROR_CODE, IntegrationError } from "./error.js";
|
|
3
|
-
import { INTEGRATION_SETTINGS_INPUT_KIND, REPOSITORY_SETTINGS_UPDATE_KIND, } from "./values.js";
|
|
3
|
+
import { INTEGRATION_SETTINGS_INPUT_KIND, REPOSITORY_REMOTE_RESOLUTION_KIND, REPOSITORY_SETTINGS_UPDATE_KIND, } from "./values.js";
|
|
4
4
|
export function createIntegrationDefinitionCatalog(definitions) {
|
|
5
5
|
return new DefaultIntegrationDefinitionCatalog(definitions);
|
|
6
6
|
}
|
|
@@ -39,13 +39,20 @@ class DefaultIntegrationDefinitionCatalog {
|
|
|
39
39
|
this.decodeSettings(definition, settings);
|
|
40
40
|
return settings;
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
projectRepositoryScope(id, settings) {
|
|
43
43
|
const definition = this.requireDefinition(id);
|
|
44
44
|
const adapter = definition.repositoryScope;
|
|
45
45
|
if (adapter === undefined) {
|
|
46
46
|
throw unsupported(definition.id, "repository settings");
|
|
47
47
|
}
|
|
48
|
-
return adapter.
|
|
48
|
+
return adapter.project(this.decodeSettings(definition, settings));
|
|
49
|
+
}
|
|
50
|
+
resolveRepositoryRemote(id, remoteUrl) {
|
|
51
|
+
const definition = this.requireDefinition(id);
|
|
52
|
+
const adapter = definition.repositoryScope;
|
|
53
|
+
return adapter === undefined
|
|
54
|
+
? { kind: REPOSITORY_REMOTE_RESOLUTION_KIND.unmatched }
|
|
55
|
+
: adapter.resolveRemote(remoteUrl);
|
|
49
56
|
}
|
|
50
57
|
requireDefinition(id) {
|
|
51
58
|
const definition = this.definitions.get(id);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { DoctorCheck } from "../login.js";
|
|
2
|
-
import type { Repository,
|
|
2
|
+
import type { Repository, WorkItems } from "../model.js";
|
|
3
3
|
import type { HttpTransport } from "../transport/http-transport.js";
|
|
4
4
|
import { type CodeHostStrategy } from "./strategy.js";
|
|
5
5
|
export { createCodeHostAccount } from "./account.js";
|
|
6
|
+
export { createCodeHostRepositoryHost } from "./repository-host.js";
|
|
6
7
|
export type CodeHostSession = {
|
|
7
8
|
readonly transport: HttpTransport;
|
|
8
9
|
readonly strategy: CodeHostStrategy;
|
|
9
10
|
};
|
|
10
11
|
export declare function createCodeHostWorkItems(session: CodeHostSession): WorkItems;
|
|
11
12
|
export declare function createCodeHostRepository(session: CodeHostSession): Repository;
|
|
12
|
-
export declare function createCodeHostRepositoryHost(session: CodeHostSession): RepositoryHost;
|
|
13
13
|
export declare function probeCodeHostDoctor(session: CodeHostSession): Promise<DoctorCheck[]>;
|
|
14
14
|
//# sourceMappingURL=facets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"facets.d.ts","sourceRoot":"","sources":["../../src/code-hosts/facets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAQV,UAAU,
|
|
1
|
+
{"version":3,"file":"facets.d.ts","sourceRoot":"","sources":["../../src/code-hosts/facets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAQV,UAAU,EAKV,SAAS,EACV,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAqCpE,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,eAAe,CAAC;AAavB,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAkBpE,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACrC,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,SAAS,CA0I3E;AAiKD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,eAAe,GAAG,UAAU,CA8D7E;AA0ID,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,WAAW,EAAE,CAAC,CA2DxB"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { INTEGRATION_ERROR_CODE, IntegrationError, isIntegrationError, withIntegrationIdentity, } from "../error.js";
|
|
2
2
|
import { commentReaction, } from "../ids.js";
|
|
3
3
|
import { collectPaginated } from "../transport/collect.js";
|
|
4
|
-
import { DOCTOR_CHECK_STATUS,
|
|
5
|
-
import { ownerKindOf } from "./account.js";
|
|
4
|
+
import { DOCTOR_CHECK_STATUS, PULL_REQUEST_REVIEW_CONTEXT_AVAILABILITY, WORK_ITEM_KIND, WORK_ITEM_QUERY_STATE, WORK_ITEM_STATE, } from "../values.js";
|
|
6
5
|
import { commentIdentity } from "./helpers.js";
|
|
7
6
|
import { normalizeComment, normalizeCommit, normalizePullRequest, normalizeWorkItem, } from "./normalize.js";
|
|
7
|
+
import { normalizeRepositoryInfo } from "./repository-info.js";
|
|
8
8
|
import { rawChangedFileListCodec, rawCommentCodec, rawCommentListCodec, rawCommitListCodec, rawCompareCodec, rawFileCodec, rawLabelCodec, rawLabelListCodec, rawMilestoneListCodec, rawPullRequestCodec, rawPullRequestListCodec, rawReactionListCodec, rawRepositoryCodec, rawViewerCodec, rawWorkItemCodec, rawWorkItemListCodec, rawWorkItemSearchCodec, } from "./schemas.js";
|
|
9
9
|
import { CODE_HOST_CHANGE_FEED_KIND, refNumber, } from "./strategy.js";
|
|
10
10
|
import { advanceTimestampChangeFeed, timestampChangeFeedBeginningPosition, timestampChangeFeedPositionAt, timestampChangeFeedQueryBoundary, } from "./timestamp-change-feed.js";
|
|
@@ -13,14 +13,13 @@ import { CODE_HOST_LABEL_KIND } from "./values.js";
|
|
|
13
13
|
// in ./account.js; re-exported here so the provider strategies keep a single
|
|
14
14
|
// facets entry point.
|
|
15
15
|
export { createCodeHostAccount } from "./account.js";
|
|
16
|
+
export { createCodeHostRepositoryHost } from "./repository-host.js";
|
|
16
17
|
const DOCTOR_CHECK_ID = {
|
|
17
18
|
authenticated: "authenticated",
|
|
18
19
|
reachable: "reachable",
|
|
19
|
-
scopes: "scopes",
|
|
20
20
|
scopeAccess: "scope-access",
|
|
21
21
|
};
|
|
22
22
|
const REQUEST_FAILED_DETAIL = "request failed";
|
|
23
|
-
const SCOPES_UNAVAILABLE_DETAIL = "The host did not expose token scopes in the probe response.";
|
|
24
23
|
const COMPARE_STATUS = {
|
|
25
24
|
identical: "identical",
|
|
26
25
|
behind: "behind",
|
|
@@ -221,13 +220,7 @@ export function createCodeHostRepository(session) {
|
|
|
221
220
|
return {
|
|
222
221
|
info: async () => {
|
|
223
222
|
const raw = await transport.request(strategy.paths.repository(repository), rawRepositoryCodec);
|
|
224
|
-
return
|
|
225
|
-
ref: repository,
|
|
226
|
-
defaultBranch: raw.defaultBranch,
|
|
227
|
-
url: raw.url,
|
|
228
|
-
isPrivate: raw.isPrivate,
|
|
229
|
-
ownerKind: ownerKindOf(raw, strategy.ownerKind),
|
|
230
|
-
};
|
|
223
|
+
return normalizeRepositoryInfo(raw, repository, strategy.ownerKind);
|
|
231
224
|
},
|
|
232
225
|
pullRequests: createPullRequests(session, normalizePr, getByRef),
|
|
233
226
|
files: {
|
|
@@ -260,38 +253,6 @@ export function createCodeHostRepository(session) {
|
|
|
260
253
|
},
|
|
261
254
|
};
|
|
262
255
|
}
|
|
263
|
-
export function createCodeHostRepositoryHost(session) {
|
|
264
|
-
const { transport, strategy } = session;
|
|
265
|
-
const normalizeRepository = (raw, ref) => ({
|
|
266
|
-
ref,
|
|
267
|
-
defaultBranch: raw.defaultBranch,
|
|
268
|
-
url: raw.url,
|
|
269
|
-
isPrivate: raw.isPrivate,
|
|
270
|
-
ownerKind: ownerKindOf(raw, strategy.ownerKind),
|
|
271
|
-
});
|
|
272
|
-
const find = async (ref) => {
|
|
273
|
-
const raw = await transport.requestOptional(strategy.paths.repository(ref), rawRepositoryCodec);
|
|
274
|
-
return raw === null ? null : normalizeRepository(raw, ref);
|
|
275
|
-
};
|
|
276
|
-
return {
|
|
277
|
-
find,
|
|
278
|
-
ensure: async (input) => {
|
|
279
|
-
const { ref } = input;
|
|
280
|
-
const existing = await find(ref);
|
|
281
|
-
if (existing !== null) {
|
|
282
|
-
return {
|
|
283
|
-
kind: ENSURE_REPOSITORY_RESULT_KIND.existing,
|
|
284
|
-
repository: existing,
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
const raw = await transport.request(await strategy.provisionRequest(transport, input), rawRepositoryCodec);
|
|
288
|
-
return {
|
|
289
|
-
kind: ENSURE_REPOSITORY_RESULT_KIND.created,
|
|
290
|
-
repository: normalizeRepository(raw, ref),
|
|
291
|
-
};
|
|
292
|
-
},
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
256
|
function createPullRequests(session, normalizePr, getByRef) {
|
|
296
257
|
const { transport, strategy } = session;
|
|
297
258
|
return {
|
|
@@ -425,11 +386,6 @@ export async function probeCodeHostDoctor(session) {
|
|
|
425
386
|
detail: error instanceof Error ? error.message : REQUEST_FAILED_DETAIL,
|
|
426
387
|
});
|
|
427
388
|
}
|
|
428
|
-
checks.push({
|
|
429
|
-
id: DOCTOR_CHECK_ID.scopes,
|
|
430
|
-
status: DOCTOR_CHECK_STATUS.warn,
|
|
431
|
-
detail: SCOPES_UNAVAILABLE_DETAIL,
|
|
432
|
-
});
|
|
433
389
|
return checks;
|
|
434
390
|
}
|
|
435
391
|
function createReactions(session) {
|
|
@@ -130,7 +130,6 @@ function projectGiteaPullRequestFeedback(input) {
|
|
|
130
130
|
...input.conversation.map(projectGiteaConversationFeedback),
|
|
131
131
|
...input.reviews
|
|
132
132
|
.filter(isSubmittedGiteaReview)
|
|
133
|
-
.filter((review) => (review.body ?? "").trim().length > 0)
|
|
134
133
|
.map(projectGiteaReviewFeedback),
|
|
135
134
|
...input.inline.map(projectGiteaInlineFeedback),
|
|
136
135
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitea.d.ts","sourceRoot":"","sources":["../../src/code-hosts/gitea.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gitea.d.ts","sourceRoot":"","sources":["../../src/code-hosts/gitea.ts"],"names":[],"mappings":"AAqCA,OAAO,EACL,KAAK,eAAe,EAMrB,MAAM,aAAa,CAAC;AA2BrB,eAAO,MAAM,oBAAoB,2DAAyB,CAAC;AAO3D,eAAO,MAAM,oBAAoB,6DAGvB,CAAC;AACX,eAAO,MAAM,2BAA2B;;;CAGA,CAAC;AAEzC,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAiIF,wBAAgB,KAAK,gJAqDpB"}
|
package/dist/code-hosts/gitea.js
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import { createSchemaRuntimeCodec } from "@alpacakit/core";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { bearerMaterialHandlers } from "../auth.js";
|
|
5
|
-
import { defineIntegration } from "../definition.js";
|
|
5
|
+
import { defineIntegration, } from "../definition.js";
|
|
6
6
|
import { INTEGRATION_ERROR_CODE, IntegrationError, isIntegrationError, } from "../error.js";
|
|
7
7
|
import { integrationId } from "../ids.js";
|
|
8
8
|
import { collectPaginated } from "../transport/collect.js";
|
|
9
9
|
import { HttpTransport } from "../transport/http-transport.js";
|
|
10
10
|
import { LinkHeaderPager } from "../transport/pager.js";
|
|
11
|
-
import { AUTHORIZATION_SCHEME, GIT_PROTOCOL, HTTP_METHOD, MERGE_METHOD, OWNER_KIND, PULL_REQUEST_STATE, REPOSITORY_SETTINGS_UPDATE_KIND, WORK_ITEM_KIND, WORK_ITEM_QUERY_STATE, WORK_ITEM_STATE, } from "../values.js";
|
|
11
|
+
import { AUTHORIZATION_SCHEME, GIT_PROTOCOL, HTTP_METHOD, MERGE_METHOD, OWNER_KIND, PULL_REQUEST_STATE, REPOSITORY_REMOTE_RESOLUTION_KIND, REPOSITORY_SETTINGS_UPDATE_KIND, WORK_ITEM_KIND, WORK_ITEM_QUERY_STATE, WORK_ITEM_STATE, } from "../values.js";
|
|
12
12
|
import { createCodeHostAccount, createCodeHostRepository, createCodeHostRepositoryHost, createCodeHostWorkItems, probeCodeHostDoctor, } from "./facets.js";
|
|
13
13
|
import { projectGiteaPullRequestStatus, readGiteaPullRequest, readGiteaPullRequestReviews, readGiteaPullRequestSnapshot, } from "./gitea-pull-request-snapshot.js";
|
|
14
|
-
import { ambientToken,
|
|
14
|
+
import { ambientToken, hasRepositoryNameConflictDetail, orgOrUserRepositoryRequest, } from "./helpers.js";
|
|
15
15
|
import { normalizeDependencyIssue } from "./normalize.js";
|
|
16
16
|
import { rawGiteaDependencyListCodec, rawGiteaLabelCodec, rawGiteaLabelListCodec, } from "./schemas.js";
|
|
17
17
|
import { CODE_HOST_CHANGE_FEED_KIND, refNumber } from "./strategy.js";
|
|
@@ -50,12 +50,92 @@ const settingsSchema = z
|
|
|
50
50
|
baseUrl: settings.baseUrl.replace(/\/$/, ""),
|
|
51
51
|
}));
|
|
52
52
|
const cursorCodec = createTimestampChangeFeedCursorCodec(GITEA_INTEGRATION_ID);
|
|
53
|
+
function resolveGiteaRemote(remoteUrl) {
|
|
54
|
+
const parsed = parseCanonicalHttpUrl(remoteUrl);
|
|
55
|
+
if (parsed.kind === REPOSITORY_REMOTE_RESOLUTION_KIND.rejected)
|
|
56
|
+
return parsed;
|
|
57
|
+
if (parsed.segments.length < 2) {
|
|
58
|
+
return rejectedRemote("Gitea remote path must end with an owner and repository.");
|
|
59
|
+
}
|
|
60
|
+
const repositorySegment = parsed.segments.at(-1);
|
|
61
|
+
const repository = repositorySegment.endsWith(".git")
|
|
62
|
+
? repositorySegment.slice(0, -4)
|
|
63
|
+
: repositorySegment;
|
|
64
|
+
const owner = parsed.segments.at(-2);
|
|
65
|
+
if (repository.length === 0) {
|
|
66
|
+
return rejectedRemote("Gitea remote repository must not be empty.");
|
|
67
|
+
}
|
|
68
|
+
const installationPath = parsed.segments.slice(0, -2);
|
|
69
|
+
return {
|
|
70
|
+
kind: REPOSITORY_REMOTE_RESOLUTION_KIND.matched,
|
|
71
|
+
repository: { owner, name: repository },
|
|
72
|
+
baseUrl: canonicalHttpUrl(parsed.origin, installationPath),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function parseCanonicalHttpUrl(remoteUrl) {
|
|
76
|
+
let url;
|
|
77
|
+
try {
|
|
78
|
+
url = new URL(remoteUrl);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return rejectedRemote("Gitea remote must be an absolute HTTP(S) URL.");
|
|
82
|
+
}
|
|
83
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
84
|
+
return rejectedRemote("Gitea remote must use HTTP or HTTPS.");
|
|
85
|
+
}
|
|
86
|
+
if (url.username !== "" ||
|
|
87
|
+
url.password !== "" ||
|
|
88
|
+
url.search !== "" ||
|
|
89
|
+
url.hash !== "") {
|
|
90
|
+
return rejectedRemote("Gitea remote must not contain credentials, a query, or a fragment.");
|
|
91
|
+
}
|
|
92
|
+
const encodedSegments = url.pathname === "/" ? [] : url.pathname.split("/").slice(1);
|
|
93
|
+
if (encodedSegments.some((segment) => segment.length === 0)) {
|
|
94
|
+
return rejectedRemote("Gitea remote path contains an empty segment.");
|
|
95
|
+
}
|
|
96
|
+
const segments = [];
|
|
97
|
+
for (const encoded of encodedSegments) {
|
|
98
|
+
let segment;
|
|
99
|
+
try {
|
|
100
|
+
segment = decodeURIComponent(encoded);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return rejectedRemote("Gitea remote path contains invalid encoding.");
|
|
104
|
+
}
|
|
105
|
+
if (segment === "." ||
|
|
106
|
+
segment === ".." ||
|
|
107
|
+
segment.includes("/") ||
|
|
108
|
+
segment.includes("\\")) {
|
|
109
|
+
return rejectedRemote("Gitea remote path contains an unsafe segment.");
|
|
110
|
+
}
|
|
111
|
+
segments.push(segment);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
kind: REPOSITORY_REMOTE_RESOLUTION_KIND.matched,
|
|
115
|
+
origin: url.origin,
|
|
116
|
+
segments,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function canonicalHttpUrl(origin, segments) {
|
|
120
|
+
return segments.length === 0
|
|
121
|
+
? origin
|
|
122
|
+
: `${origin}/${segments.map((segment) => encodeURIComponent(segment)).join("/")}`;
|
|
123
|
+
}
|
|
124
|
+
function canonicalGiteaBaseUrl(baseUrl) {
|
|
125
|
+
const parsed = parseCanonicalHttpUrl(baseUrl);
|
|
126
|
+
return parsed.kind === REPOSITORY_REMOTE_RESOLUTION_KIND.rejected
|
|
127
|
+
? null
|
|
128
|
+
: canonicalHttpUrl(parsed.origin, parsed.segments);
|
|
129
|
+
}
|
|
130
|
+
function rejectedRemote(detail) {
|
|
131
|
+
return { kind: REPOSITORY_REMOTE_RESOLUTION_KIND.rejected, detail };
|
|
132
|
+
}
|
|
53
133
|
export function gitea() {
|
|
54
134
|
return defineIntegration({
|
|
55
135
|
id: GITEA_INTEGRATION_ID,
|
|
56
136
|
settingsCodec: createSchemaRuntimeCodec(settingsSchema),
|
|
57
|
-
remoteMatch: (remoteUrl, settings) => matchesRemote(remoteUrl, new URL(settings.baseUrl).hostname, `${settings.owner}/${settings.repository}`),
|
|
58
137
|
repositoryScope: {
|
|
138
|
+
resolveRemote: resolveGiteaRemote,
|
|
59
139
|
applySettings: (input) => {
|
|
60
140
|
if (input.kind === REPOSITORY_SETTINGS_UPDATE_KIND.baseUrl) {
|
|
61
141
|
return {
|
|
@@ -71,9 +151,12 @@ export function gitea() {
|
|
|
71
151
|
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
72
152
|
};
|
|
73
153
|
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
154
|
+
project: (settings) => ({
|
|
155
|
+
repository: {
|
|
156
|
+
owner: settings.owner,
|
|
157
|
+
name: settings.repository,
|
|
158
|
+
},
|
|
159
|
+
baseUrl: canonicalGiteaBaseUrl(settings.baseUrl) ?? settings.baseUrl,
|
|
77
160
|
}),
|
|
78
161
|
},
|
|
79
162
|
auth: {
|
|
@@ -154,7 +237,8 @@ function giteaStrategy(settings) {
|
|
|
154
237
|
number,
|
|
155
238
|
pager: GITEA_PAGER,
|
|
156
239
|
}),
|
|
157
|
-
|
|
240
|
+
createNewRequest: orgOrUserRepositoryRequest,
|
|
241
|
+
isCreateNewConflict: isGiteaRepositoryCreateConflict,
|
|
158
242
|
workItemRelations: (transport) => createGiteaRelations(transport, repositoryPath, settings),
|
|
159
243
|
workItemCreateRequest: async (transport, input) => ({
|
|
160
244
|
method: HTTP_METHOD.post,
|
|
@@ -338,11 +422,9 @@ function giteaStrategy(settings) {
|
|
|
338
422
|
resource: CODE_HOST_RESOURCE.authenticatedUser,
|
|
339
423
|
}),
|
|
340
424
|
membership: {
|
|
341
|
-
list: (
|
|
425
|
+
list: () => ({
|
|
342
426
|
method: HTTP_METHOD.get,
|
|
343
|
-
path:
|
|
344
|
-
? `/orgs/${encodeURIComponent(settings.owner)}/members`
|
|
345
|
-
: `${repositoryPath}/collaborators`,
|
|
427
|
+
path: `${repositoryPath}/collaborators`,
|
|
346
428
|
query: { limit: MAX_PAGE_SIZE },
|
|
347
429
|
resource: CODE_HOST_RESOURCE.membership,
|
|
348
430
|
}),
|
|
@@ -481,6 +563,12 @@ async function loadPalette(transport, repositoryPath) {
|
|
|
481
563
|
resource: CODE_HOST_RESOURCE.labels,
|
|
482
564
|
}, rawGiteaLabelListCodec, GITEA_PAGER);
|
|
483
565
|
}
|
|
566
|
+
function isGiteaRepositoryCreateConflict(error) {
|
|
567
|
+
return (isIntegrationError(error, INTEGRATION_ERROR_CODE.conflict) &&
|
|
568
|
+
(error.data.status === 409 ||
|
|
569
|
+
(error.data.status === 422 &&
|
|
570
|
+
hasRepositoryNameConflictDetail(error.data.detail))));
|
|
571
|
+
}
|
|
484
572
|
function createGiteaRelations(transport, repositoryPath, settings) {
|
|
485
573
|
return {
|
|
486
574
|
listBlockedBy: async (ref) => (await collectPaginated(transport, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/code-hosts/github.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/code-hosts/github.ts"],"names":[],"mappings":"AA0CA,OAAO,EACL,KAAK,eAAe,EAMrB,MAAM,aAAa,CAAC;AAwBrB,eAAO,MAAM,qBAAqB,4DAA0B,CAAC;AA8B7D,eAAO,MAAM,qBAAqB,qCAAsC,CAAC;AACzE,eAAO,MAAM,4BAA4B;;;CAGD,CAAC;AAEzC,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AA6LF,wBAAgB,MAAM,kJA4DrB"}
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import { createSchemaRuntimeCodec } from "@alpacakit/core";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { bearerMaterialHandlers } from "../auth.js";
|
|
5
|
-
import { defineIntegration } from "../definition.js";
|
|
6
|
-
import { INTEGRATION_ERROR_CODE, IntegrationError } from "../error.js";
|
|
5
|
+
import { defineIntegration, } from "../definition.js";
|
|
6
|
+
import { INTEGRATION_ERROR_CODE, IntegrationError, isIntegrationError, } from "../error.js";
|
|
7
7
|
import { integrationId } from "../ids.js";
|
|
8
8
|
import { collectPaginated } from "../transport/collect.js";
|
|
9
9
|
import { HttpTransport } from "../transport/http-transport.js";
|
|
10
10
|
import { LinkHeaderPager } from "../transport/pager.js";
|
|
11
|
-
import { AUTHORIZATION_SCHEME, COMMENT_KIND, GIT_PROTOCOL, HTTP_METHOD, MERGE_METHOD, MERGE_STATE_STATUS, MERGEABILITY, OWNER_KIND, PULL_REQUEST_STATE, REPOSITORY_SETTINGS_UPDATE_KIND, REVIEW_DECISION, WORK_ITEM_QUERY_STATE, WORK_ITEM_STATE, } from "../values.js";
|
|
11
|
+
import { AUTHORIZATION_SCHEME, COMMENT_KIND, GIT_PROTOCOL, HTTP_METHOD, MERGE_METHOD, MERGE_STATE_STATUS, MERGEABILITY, OWNER_KIND, PULL_REQUEST_STATE, REPOSITORY_REMOTE_RESOLUTION_KIND, REPOSITORY_SETTINGS_UPDATE_KIND, REVIEW_DECISION, WORK_ITEM_QUERY_STATE, WORK_ITEM_STATE, } from "../values.js";
|
|
12
12
|
import { createCodeHostAccount, createCodeHostRepository, createCodeHostRepositoryHost, createCodeHostWorkItems, probeCodeHostDoctor, } from "./facets.js";
|
|
13
13
|
import { githubDeviceLogin } from "./github-login.js";
|
|
14
|
-
import { ambientToken,
|
|
14
|
+
import { ambientToken, hasRepositoryNameConflictDetail, orgOrUserRepositoryRequest, parseGitRemote, } from "./helpers.js";
|
|
15
15
|
import { normalizeDependencyIssue } from "./normalize.js";
|
|
16
16
|
import { rawDependencyIssueListCodec, rawPullRequestCodec, rawReactionListCodec, rawWorkItemCodec, } from "./schemas.js";
|
|
17
17
|
import { CODE_HOST_CHANGE_FEED_KIND, refNumber } from "./strategy.js";
|
|
@@ -65,7 +65,7 @@ const githubSettingsSchema = z
|
|
|
65
65
|
.transform((settings) => ({
|
|
66
66
|
owner: settings.owner,
|
|
67
67
|
repository: settings.repository,
|
|
68
|
-
baseUrl: settings.baseUrl ?? GITHUB_API_URL,
|
|
68
|
+
baseUrl: (settings.baseUrl ?? GITHUB_API_URL).replace(/\/$/, ""),
|
|
69
69
|
}));
|
|
70
70
|
const cursorCodec = createTimestampChangeFeedCursorCodec(GITHUB_INTEGRATION_ID);
|
|
71
71
|
const githubPullRequestStatusCodec = createSchemaRuntimeCodec(z
|
|
@@ -165,18 +165,59 @@ const githubLinkedBranchMutationCodec = createSchemaRuntimeCodec(z
|
|
|
165
165
|
.strip(),
|
|
166
166
|
})
|
|
167
167
|
.strip());
|
|
168
|
+
function resolveGitHubBaseUrls(input) {
|
|
169
|
+
if ("webOrigin" in input) {
|
|
170
|
+
return input.webOrigin === "https://github.com"
|
|
171
|
+
? { webOrigin: input.webOrigin, apiBaseUrl: GITHUB_API_URL }
|
|
172
|
+
: {
|
|
173
|
+
webOrigin: input.webOrigin,
|
|
174
|
+
apiBaseUrl: `${input.webOrigin}/api/v3`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const apiBaseUrl = new URL(input.apiBaseUrl).toString().replace(/\/$/u, "");
|
|
178
|
+
return apiBaseUrl === GITHUB_API_URL
|
|
179
|
+
? { webOrigin: "https://github.com", apiBaseUrl }
|
|
180
|
+
: {
|
|
181
|
+
webOrigin: apiBaseUrl.replace(/\/api\/v3\/?$/u, ""),
|
|
182
|
+
apiBaseUrl,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function resolveGitHubRemote(remoteUrl) {
|
|
186
|
+
const parsed = parseGitRemote(remoteUrl);
|
|
187
|
+
if (parsed.kind === "rejected") {
|
|
188
|
+
return {
|
|
189
|
+
kind: REPOSITORY_REMOTE_RESOLUTION_KIND.rejected,
|
|
190
|
+
detail: `GitHub remote ${parsed.detail}.`,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (parsed.pathSegments.length !== 2) {
|
|
194
|
+
return {
|
|
195
|
+
kind: REPOSITORY_REMOTE_RESOLUTION_KIND.rejected,
|
|
196
|
+
detail: "GitHub remote path must contain an owner and repository.",
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const [owner, repositorySegment] = parsed.pathSegments;
|
|
200
|
+
const repository = repositorySegment.endsWith(".git")
|
|
201
|
+
? repositorySegment.slice(0, -4)
|
|
202
|
+
: repositorySegment;
|
|
203
|
+
if (repository === "") {
|
|
204
|
+
return {
|
|
205
|
+
kind: REPOSITORY_REMOTE_RESOLUTION_KIND.rejected,
|
|
206
|
+
detail: "GitHub remote repository must not be empty.",
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
kind: REPOSITORY_REMOTE_RESOLUTION_KIND.matched,
|
|
211
|
+
repository: { owner, name: repository },
|
|
212
|
+
baseUrl: resolveGitHubBaseUrls({ webOrigin: parsed.webOrigin }).apiBaseUrl,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
168
215
|
export function github() {
|
|
169
216
|
return defineIntegration({
|
|
170
217
|
id: GITHUB_INTEGRATION_ID,
|
|
171
218
|
settingsCodec: createSchemaRuntimeCodec(githubSettingsSchema),
|
|
172
|
-
remoteMatch: (remoteUrl, settings) => {
|
|
173
|
-
const base = new URL(settings.baseUrl);
|
|
174
|
-
const host = base.hostname === "api.github.com"
|
|
175
|
-
? "github.com"
|
|
176
|
-
: base.hostname.replace(/^api\./, "");
|
|
177
|
-
return matchesRemote(remoteUrl, host, `${settings.owner}/${settings.repository}`);
|
|
178
|
-
},
|
|
179
219
|
repositoryScope: {
|
|
220
|
+
resolveRemote: resolveGitHubRemote,
|
|
180
221
|
applySettings: (input) => {
|
|
181
222
|
if (input.kind === REPOSITORY_SETTINGS_UPDATE_KIND.baseUrl) {
|
|
182
223
|
return {
|
|
@@ -185,16 +226,20 @@ export function github() {
|
|
|
185
226
|
baseUrl: input.baseUrl,
|
|
186
227
|
};
|
|
187
228
|
}
|
|
188
|
-
const baseUrl = input.baseUrl ?? input.current?.baseUrl;
|
|
229
|
+
const baseUrl = input.baseUrl ?? input.current?.baseUrl ?? GITHUB_API_URL;
|
|
189
230
|
return {
|
|
190
231
|
owner: input.repository.owner,
|
|
191
232
|
repository: input.repository.name,
|
|
192
|
-
|
|
233
|
+
baseUrl,
|
|
193
234
|
};
|
|
194
235
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
236
|
+
project: (settings) => ({
|
|
237
|
+
repository: {
|
|
238
|
+
owner: settings.owner,
|
|
239
|
+
name: settings.repository,
|
|
240
|
+
},
|
|
241
|
+
baseUrl: resolveGitHubBaseUrls({ apiBaseUrl: settings.baseUrl })
|
|
242
|
+
.apiBaseUrl,
|
|
198
243
|
}),
|
|
199
244
|
},
|
|
200
245
|
auth: {
|
|
@@ -240,9 +285,7 @@ function createGitHubSession(settings, authorization, ports, connectionId) {
|
|
|
240
285
|
// biome-ignore lint/complexity/noExcessiveLinesPerFunction: The provider request map stays together so endpoint behavior remains reviewable as one strategy.
|
|
241
286
|
function githubStrategy(settings) {
|
|
242
287
|
const repositoryPath = `/repos/${encodeURIComponent(settings.owner)}/${encodeURIComponent(settings.repository)}`;
|
|
243
|
-
const webBaseUrl = settings.baseUrl
|
|
244
|
-
? `https://github.com/${settings.owner}/${settings.repository}`
|
|
245
|
-
: `${settings.baseUrl.replace(/\/api\/v3\/?$/, "")}/${settings.owner}/${settings.repository}`;
|
|
288
|
+
const webBaseUrl = `${resolveGitHubBaseUrls({ apiBaseUrl: settings.baseUrl }).webOrigin}/${settings.owner}/${settings.repository}`;
|
|
246
289
|
const issueBody = (input) => ({
|
|
247
290
|
...(input.title === undefined ? {} : { title: input.title }),
|
|
248
291
|
...(input.body === undefined ? {} : { body: input.body }),
|
|
@@ -314,7 +357,8 @@ function githubStrategy(settings) {
|
|
|
314
357
|
resource: CODE_HOST_RESOURCE.labels,
|
|
315
358
|
}),
|
|
316
359
|
},
|
|
317
|
-
|
|
360
|
+
createNewRequest: orgOrUserRepositoryRequest,
|
|
361
|
+
isCreateNewConflict: isGitHubRepositoryCreateConflict,
|
|
318
362
|
workItemCreateRequest: async (_transport, input) => ({
|
|
319
363
|
method: HTTP_METHOD.post,
|
|
320
364
|
path: `${repositoryPath}/issues`,
|
|
@@ -644,6 +688,12 @@ function githubStrategy(settings) {
|
|
|
644
688
|
},
|
|
645
689
|
};
|
|
646
690
|
}
|
|
691
|
+
function isGitHubRepositoryCreateConflict(error) {
|
|
692
|
+
return (isIntegrationError(error, INTEGRATION_ERROR_CODE.conflict) &&
|
|
693
|
+
(error.data.status === 409 ||
|
|
694
|
+
(error.data.status === 422 &&
|
|
695
|
+
hasRepositoryNameConflictDetail(error.data.detail))));
|
|
696
|
+
}
|
|
647
697
|
function missingGitHubNodeId(transport, resource) {
|
|
648
698
|
return new IntegrationError({
|
|
649
699
|
code: INTEGRATION_ERROR_CODE.failed,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../src/code-hosts/gitlab.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../src/code-hosts/gitlab.ts"],"names":[],"mappings":"AAgDA,OAAO,EACL,KAAK,eAAe,EAMrB,MAAM,aAAa,CAAC;AAgCrB,eAAO,MAAM,qBAAqB,4DAA0B,CAAC;AA8B7D,eAAO,MAAM,qBAAqB,sCAAuC,CAAC;AAC1E,eAAO,MAAM,4BAA4B;;;CAGD,CAAC;AAEzC,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AA0EF,wBAAgB,MAAM,kJAiErB"}
|