feat(app-connection): BitBucket app connection

This commit is contained in:
x032205
2025-07-02 17:56:48 -04:00
parent bb59bb1868
commit 62ad82f7b1
25 changed files with 413 additions and 17 deletions
@@ -0,0 +1,3 @@
export enum BitBucketConnectionMethod {
ApiToken = "api-token"
}
@@ -0,0 +1,40 @@
import { AxiosError } from "axios";
import { request } from "@app/lib/config/request";
import { BadRequestError } from "@app/lib/errors";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { BitBucketConnectionMethod } from "./bitbucket-connection-enums";
import { TBitBucketConnectionConfig } from "./bitbucket-connection-types";
export const getBitBucketConnectionListItem = () => {
return {
name: "BitBucket" as const,
app: AppConnection.BitBucket as const,
methods: Object.values(BitBucketConnectionMethod) as [BitBucketConnectionMethod.ApiToken]
};
};
export const validateBitBucketConnectionCredentials = async (config: TBitBucketConnectionConfig) => {
const { email, apiToken } = config.credentials;
try {
await request.get("https://api.bitbucket.org/2.0/user", {
headers: {
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
Accept: "application/json"
}
});
} catch (error: unknown) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to validate credentials: ${error.message || "Unknown error"}`
});
}
throw new BadRequestError({
message: "Unable to validate connection: verify credentials"
});
}
return config.credentials;
};
@@ -0,0 +1,61 @@
import z from "zod";
import { AppConnections } from "@app/lib/api-docs";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
BaseAppConnectionSchema,
GenericCreateAppConnectionFieldsSchema,
GenericUpdateAppConnectionFieldsSchema
} from "@app/services/app-connection/app-connection-schemas";
import { BitBucketConnectionMethod } from "./bitbucket-connection-enums";
export const BitBucketConnectionAccessTokenCredentialsSchema = z.object({
apiToken: z.string().trim().min(1, "API Token required").describe(AppConnections.CREDENTIALS.BITBUCKET.apiToken),
email: z.string().email().trim().min(1, "Email required").describe(AppConnections.CREDENTIALS.BITBUCKET.email)
});
const BaseBitBucketConnectionSchema = BaseAppConnectionSchema.extend({ app: z.literal(AppConnection.BitBucket) });
export const BitBucketConnectionSchema = BaseBitBucketConnectionSchema.extend({
method: z.literal(BitBucketConnectionMethod.ApiToken),
credentials: BitBucketConnectionAccessTokenCredentialsSchema
});
export const SanitizedBitBucketConnectionSchema = z.discriminatedUnion("method", [
BaseBitBucketConnectionSchema.extend({
method: z.literal(BitBucketConnectionMethod.ApiToken),
credentials: BitBucketConnectionAccessTokenCredentialsSchema.pick({
email: true
})
})
]);
export const ValidateBitBucketConnectionCredentialsSchema = z.discriminatedUnion("method", [
z.object({
method: z
.literal(BitBucketConnectionMethod.ApiToken)
.describe(AppConnections.CREATE(AppConnection.BitBucket).method),
credentials: BitBucketConnectionAccessTokenCredentialsSchema.describe(
AppConnections.CREATE(AppConnection.BitBucket).credentials
)
})
]);
export const CreateBitBucketConnectionSchema = ValidateBitBucketConnectionCredentialsSchema.and(
GenericCreateAppConnectionFieldsSchema(AppConnection.BitBucket)
);
export const UpdateBitBucketConnectionSchema = z
.object({
credentials: BitBucketConnectionAccessTokenCredentialsSchema.optional().describe(
AppConnections.UPDATE(AppConnection.BitBucket).credentials
)
})
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.BitBucket));
export const BitBucketConnectionListItemSchema = z.object({
name: z.literal("BitBucket"),
app: z.literal(AppConnection.BitBucket),
methods: z.nativeEnum(BitBucketConnectionMethod).array()
});
@@ -0,0 +1,15 @@
import { OrgServiceActor } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums";
// import { listBitBucketVaults } from "./bitbucket-connection-fns";
import { TBitBucketConnection } from "./bitbucket-connection-types";
type TGetAppConnectionFunc = (
app: AppConnection,
connectionId: string,
actor: OrgServiceActor
) => Promise<TBitBucketConnection>;
export const bitBucketConnectionService = (_getAppConnection: TGetAppConnectionFunc) => {
return {};
};
@@ -0,0 +1,38 @@
import z from "zod";
import { DiscriminativePick } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums";
import {
BitBucketConnectionSchema,
CreateBitBucketConnectionSchema,
ValidateBitBucketConnectionCredentialsSchema
} from "./bitbucket-connection-schemas";
export type TBitBucketConnection = z.infer<typeof BitBucketConnectionSchema>;
export type TBitBucketConnectionInput = z.infer<typeof CreateBitBucketConnectionSchema> & {
app: AppConnection.BitBucket;
};
export type TValidateBitBucketConnectionCredentialsSchema = typeof ValidateBitBucketConnectionCredentialsSchema;
export type TBitBucketConnectionConfig = DiscriminativePick<
TBitBucketConnectionInput,
"method" | "app" | "credentials"
> & {
orgId: string;
};
export type TBitBucketVault = {
id: string;
name: string;
type: string;
items: number;
attributeVersion: number;
contentVersion: number;
createdAt: string;
updatedAt: string;
};
@@ -0,0 +1,4 @@
export * from "./bitbucket-connection-enums";
export * from "./bitbucket-connection-fns";
export * from "./bitbucket-connection-schemas";
export * from "./bitbucket-connection-types";