diff --git a/apps/webservice/package.json b/apps/webservice/package.json
index 6f594db06..4613c2e91 100644
--- a/apps/webservice/package.json
+++ b/apps/webservice/package.json
@@ -24,6 +24,8 @@
"@internationalized/date": "^3.5.4",
"@monaco-editor/react": "^4.6.0",
"@octokit/auth-app": "^7.1.0",
+ "@octokit/rest": "^20.1.1",
+ "@octokit/webhooks-types": "^7.5.1",
"@opentelemetry/api-logs": "^0.52.1",
"@opentelemetry/instrumentation": "^0.52.1",
"@opentelemetry/sdk-logs": "^0.52.1",
diff --git a/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/GithubConfigFile.tsx b/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/GithubConfigFile.tsx
index 3cd076bcb..040871f7e 100644
--- a/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/GithubConfigFile.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/GithubConfigFile.tsx
@@ -1,3 +1,4 @@
+import type { GithubConfigFile } from "@ctrlplane/db/schema";
import {
Card,
CardContent,
@@ -7,15 +8,9 @@ import {
} from "@ctrlplane/ui/card";
import { Separator } from "@ctrlplane/ui/separator";
-import { api } from "~/trpc/react";
-
export const GithubConfigFileSync: React.FC<{
- workspaceId?: string;
-}> = ({ workspaceId }) => {
- const configFiles = api.github.configFile.list.useQuery(workspaceId ?? "", {
- enabled: workspaceId != null,
- });
-
+ configFiles: GithubConfigFile[];
+}> = ({ configFiles }) => {
return (
@@ -31,8 +26,8 @@ export const GithubConfigFileSync: React.FC<{
- {configFiles.data?.map((configFile) => (
- {configFile.name}
+ {configFiles.map((configFile) => (
+ {configFile.path}
))}
diff --git a/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/page.tsx b/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/page.tsx
index 78037835a..3b21573a4 100644
--- a/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/page.tsx
+++ b/apps/webservice/src/app/[workspaceSlug]/settings/(settings)/workspace/integrations/(integration)/github/page.tsx
@@ -29,6 +29,11 @@ export default function GitHubIntegrationPage({
enabled: session.status === "authenticated",
});
+ const configFiles = api.github.configFile.list.useQuery(
+ workspace.data?.id ?? "",
+ { enabled: workspace.data != null },
+ );
+
return (
@@ -77,7 +82,7 @@ export default function GitHubIntegrationPage({
loading={workspace.isLoading || githubUser.isLoading}
/>
-
+
);
}
diff --git a/apps/webservice/src/app/api/github/config/handle-configs.ts b/apps/webservice/src/app/api/github/config/handle-configs.ts
new file mode 100644
index 000000000..7ae27091a
--- /dev/null
+++ b/apps/webservice/src/app/api/github/config/handle-configs.ts
@@ -0,0 +1,207 @@
+import { and, eq, inArray } from "@ctrlplane/db";
+import { db } from "@ctrlplane/db/client";
+import type {
+ GithubOrganization} from "@ctrlplane/db/schema";
+import {
+ deployment,
+ githubConfigFile,
+ system,
+ workspace,
+} from "@ctrlplane/db/schema";
+
+interface DeploymentConfig {
+ name: string;
+ slug: string;
+ system: string;
+ workspace: string;
+ description?: string;
+}
+
+interface ParsedConfig {
+ path: string;
+ repositoryName: string;
+ branch: string;
+ deployments: DeploymentConfig[];
+}
+
+export const handleNewConfigs = async (
+ newParsedConfigs: ParsedConfig[],
+ internalOrganization: GithubOrganization,
+ repositoryName: string,
+) => {
+ if (newParsedConfigs.length === 0) return;
+
+ const newConfigs = await db
+ .insert(githubConfigFile)
+ .values(
+ newParsedConfigs.map((cf) => ({
+ ...cf,
+ workspaceId: internalOrganization.workspaceId,
+ organizationId: internalOrganization.id,
+ repositoryName: repositoryName,
+ })),
+ )
+ .returning();
+
+ const newDeploymentInfo = await db
+ .select()
+ .from(system)
+ .innerJoin(workspace, eq(system.workspaceId, workspace.id))
+ .where(
+ and(
+ inArray(
+ system.slug,
+ newParsedConfigs
+ .map((d) => d.deployments.map((d) => d.system))
+ .flat(),
+ ),
+ inArray(
+ workspace.slug,
+ newParsedConfigs
+ .map((d) => d.deployments.map((d) => d.workspace))
+ .flat(),
+ ),
+ ),
+ );
+
+ const deploymentsFromNewConfigs = newParsedConfigs
+ .map((cf) =>
+ cf.deployments.map((d) => {
+ const info = newDeploymentInfo.find(
+ (i) => i.system.slug === d.system && i.workspace.slug === d.workspace,
+ );
+ if (info == null) throw new Error("Deployment info not found");
+ const { system, workspace } = info;
+
+ return {
+ ...d,
+ systemId: system.id,
+ workspaceId: workspace.id,
+ description: d.description ?? "",
+ githubConfigFileId: newConfigs.find(
+ (icf) =>
+ icf.path === cf.path && icf.repositoryName === cf.repositoryName,
+ )?.id,
+ };
+ }),
+ )
+ .flat();
+
+ await db.insert(deployment).values(deploymentsFromNewConfigs);
+};
+
+export const handleModifiedConfigs = async (
+ modifiedParsedConfigs: ParsedConfig[],
+ internalOrganization: GithubOrganization,
+ repositoryName: string,
+) => {
+ if (modifiedParsedConfigs.length === 0) return;
+ const existingConfigs = await db
+ .select()
+ .from(githubConfigFile)
+ .where(
+ and(
+ inArray(
+ githubConfigFile.path,
+ modifiedParsedConfigs.map((cf) => cf.path),
+ ),
+ eq(githubConfigFile.organizationId, internalOrganization.id),
+ eq(githubConfigFile.repositoryName, repositoryName),
+ ),
+ );
+
+ const existingDeployments = await db
+ .select()
+ .from(deployment)
+ .innerJoin(system, eq(deployment.systemId, system.id))
+ .innerJoin(workspace, eq(system.workspaceId, workspace.id))
+ .where(
+ inArray(
+ deployment.githubConfigFileId,
+ existingConfigs.map((c) => c.id),
+ ),
+ );
+
+ const deploymentsInConfigFiles = modifiedParsedConfigs
+ .map((d) => d.deployments)
+ .flat();
+
+ const removedDeployments = existingDeployments.filter(
+ (ed) =>
+ !deploymentsInConfigFiles.some(
+ (dc) =>
+ dc.slug === ed.deployment.slug &&
+ dc.system === ed.system.slug &&
+ dc.workspace === ed.workspace.slug,
+ ),
+ );
+
+ if (removedDeployments.length > 0)
+ await db.delete(deployment).where(
+ inArray(
+ deployment.id,
+ removedDeployments.map((d) => d.deployment.id),
+ ),
+ );
+
+ const newDeployments = modifiedParsedConfigs
+ .map((cf) =>
+ cf.deployments.map((d) => ({
+ ...d,
+ cf: {
+ path: cf.path,
+ repositoryName: cf.repositoryName,
+ },
+ })),
+ )
+ .flat()
+ .filter(
+ (d) =>
+ !existingDeployments.some(
+ (ed) =>
+ ed.deployment.slug === d.slug &&
+ ed.system.slug === d.system &&
+ ed.workspace.slug === d.workspace,
+ ),
+ );
+
+ if (newDeployments.length === 0) return;
+
+ const newDeploymentInfo = await db
+ .select()
+ .from(system)
+ .innerJoin(workspace, eq(system.workspaceId, workspace.id))
+ .where(
+ and(
+ inArray(
+ system.slug,
+ newDeployments.map((d) => d.system),
+ ),
+ inArray(
+ workspace.slug,
+ newDeployments.map((d) => d.workspace),
+ ),
+ ),
+ );
+
+ const newDeploymentsInsert = newDeployments.map((d) => {
+ const info = newDeploymentInfo.find(
+ (i) => i.system.slug === d.system && i.workspace.slug === d.workspace,
+ );
+ if (info == null) throw new Error("Deployment info not found");
+ const { system, workspace } = info;
+
+ return {
+ ...d,
+ systemId: system.id,
+ workspaceId: workspace.id,
+ description: d.description ?? "",
+ githubConfigFileId: existingConfigs.find(
+ (icf) =>
+ icf.path === d.cf.path && icf.repositoryName === d.cf.repositoryName,
+ )?.id,
+ };
+ });
+
+ await db.insert(deployment).values(newDeploymentsInsert);
+};
diff --git a/apps/webservice/src/app/api/github/config/route.ts b/apps/webservice/src/app/api/github/config/route.ts
new file mode 100644
index 000000000..6629a3753
--- /dev/null
+++ b/apps/webservice/src/app/api/github/config/route.ts
@@ -0,0 +1,174 @@
+import type { NextRequest } from "next/server";
+import { NextResponse } from "next/server";
+import { createAppAuth } from "@octokit/auth-app";
+import { Octokit } from "@octokit/rest";
+import type { PushEvent } from "@octokit/webhooks-types";
+import * as yaml from "js-yaml";
+import { isPresent } from "ts-is-present";
+
+import { and, eq, inArray, takeFirstOrNull } from "@ctrlplane/db";
+import { db } from "@ctrlplane/db/client";
+import { githubConfigFile, githubOrganization } from "@ctrlplane/db/schema";
+import { configFile } from "@ctrlplane/validators";
+
+import { env } from "~/env";
+import { handleModifiedConfigs, handleNewConfigs } from "./handle-configs";
+
+const getOctokitInstallation = (installationId: number) =>
+ env.GITHUB_BOT_APP_ID == null ||
+ env.GITHUB_BOT_PRIVATE_KEY == null ||
+ env.GITHUB_BOT_CLIENT_ID == null ||
+ env.GITHUB_BOT_CLIENT_SECRET == null
+ ? null
+ : new Octokit({
+ authStrategy: createAppAuth,
+ auth: {
+ appId: env.GITHUB_BOT_APP_ID,
+ privateKey: env.GITHUB_BOT_PRIVATE_KEY,
+ clientId: env.GITHUB_BOT_CLIENT_ID,
+ clientSecret: env.GITHUB_BOT_CLIENT_SECRET,
+ installationId,
+ },
+ });
+
+const isConfigFile = (path: string) =>
+ path.endsWith("ctrlplane.yaml") || path.endsWith("ctrlplane.yml");
+
+interface GetParsedConfigOptions {
+ organization: string;
+ repository: string;
+ path: string;
+ branch: string;
+}
+
+const getParsedConfig = (
+ { organization, repository, path, branch }: GetParsedConfigOptions,
+ installationOctokit: Octokit,
+) =>
+ installationOctokit.repos
+ .getContent({
+ owner: organization,
+ repo: repository,
+ path,
+ ref: branch,
+ })
+ .then(({ data }) => {
+ if (!("content" in data)) throw new Error("Invalid response data");
+ const content = Buffer.from(data.content, "base64").toString("utf-8");
+ const yamlContent = yaml.load(content);
+ const parsed = configFile.safeParse(yamlContent);
+ if (!parsed.success) throw new Error("Invalid config file");
+ return {
+ ...parsed.data,
+ repositoryName: repository,
+ path,
+ branch,
+ };
+ });
+
+const handleCommitWebhookEvent = async (event: PushEvent) => {
+ const { ref, organization, repository, commits: eventCommits } = event;
+ if (organization == null)
+ throw new Error("Event not associated with an organization");
+
+ const branch = ref.split("/").pop();
+
+ const internalOrganization = await db
+ .select()
+ .from(githubOrganization)
+ .where(eq(githubOrganization.organizationName, organization.login))
+ .then(takeFirstOrNull);
+
+ if (internalOrganization == null) throw new Error("Organization not found");
+
+ if (internalOrganization.branch !== branch) return;
+
+ const removedConfigFiles = eventCommits
+ .flatMap((v) => v.removed)
+ .filter(isConfigFile);
+
+ if (removedConfigFiles.length > 0)
+ await db
+ .delete(githubConfigFile)
+ .where(
+ and(
+ inArray(githubConfigFile.path, removedConfigFiles),
+ eq(githubConfigFile.organizationId, internalOrganization.id),
+ ),
+ );
+
+ const newConfigFiles = eventCommits
+ .flatMap((v) => v.added)
+ .filter(isConfigFile);
+ const modifiedConfigFiles = eventCommits
+ .flatMap((v) => v.modified)
+ .filter(isConfigFile);
+
+ const installationOctokit = getOctokitInstallation(
+ internalOrganization.installationId,
+ );
+
+ if (installationOctokit == null) throw new Error("GitHub bot not configured");
+
+ const [newParsedConfigs, modifiedParsedConfigs] = await Promise.all([
+ Promise.allSettled(
+ newConfigFiles.map(async (cf) => {
+ return getParsedConfig(
+ {
+ organization: internalOrganization.organizationName,
+ repository: repository.name,
+ path: cf,
+ branch: internalOrganization.branch,
+ },
+ installationOctokit,
+ );
+ }),
+ ).then((results) =>
+ results
+ .map((r) => (r.status === "fulfilled" ? r.value : null))
+ .filter(isPresent),
+ ),
+
+ Promise.allSettled(
+ modifiedConfigFiles.map(async (cf) => {
+ return getParsedConfig(
+ {
+ organization: internalOrganization.organizationName,
+ repository: repository.name,
+ path: cf,
+ branch: internalOrganization.branch,
+ },
+ installationOctokit,
+ );
+ }),
+ ).then((results) =>
+ results
+ .map((r) => (r.status === "fulfilled" ? r.value : null))
+ .filter(isPresent),
+ ),
+ ]);
+
+ await handleModifiedConfigs(
+ modifiedParsedConfigs,
+ internalOrganization,
+ repository.name,
+ );
+
+ await handleNewConfigs(
+ newParsedConfigs,
+ internalOrganization,
+ repository.name,
+ );
+};
+
+export const POST = async (req: NextRequest) => {
+ try {
+ const event = req.headers.get("x-github-event")?.toString();
+ const data = await req.json();
+
+ if (event === "push") await handleCommitWebhookEvent(data as PushEvent);
+ return new NextResponse("OK");
+ } catch (e) {
+ return new NextResponse((e as any).message, { status: 500 });
+ }
+};
diff --git a/apps/webservice/src/env.ts b/apps/webservice/src/env.ts
index bc9dec43f..de6e8f7e8 100644
--- a/apps/webservice/src/env.ts
+++ b/apps/webservice/src/env.ts
@@ -22,6 +22,8 @@ export const env = createEnv({
POSTGRES_URL: z.string().url(),
GITHUB_BOT_CLIENT_ID: z.string().optional(),
GITHUB_BOT_CLIENT_SECRET: z.string().optional(),
+ GITHUB_BOT_APP_ID: z.string().optional(),
+ GITHUB_BOT_PRIVATE_KEY: z.string().optional(),
},
/**
diff --git a/packages/api/src/router/github.ts b/packages/api/src/router/github.ts
index 4761408d0..fc02231d2 100644
--- a/packages/api/src/router/github.ts
+++ b/packages/api/src/router/github.ts
@@ -256,16 +256,9 @@ export const githubRouter = createTRPCRouter({
installation_id: org.installationId,
})
.then(async ({ data: installation }) => {
- const installationOctokit = new Octokit({
- authStrategy: createAppAuth,
- auth: {
- appId: env.GITHUB_BOT_APP_ID,
- privateKey: env.GITHUB_BOT_PRIVATE_KEY,
- clientId: env.GITHUB_BOT_CLIENT_ID,
- clientSecret: env.GITHUB_BOT_CLIENT_SECRET,
- installationId: installation.id,
- },
- });
+ const installationOctokit = getOctokitInstallation(
+ installation.id,
+ );
const installationToken = (await installationOctokit.auth({
type: "installation",
@@ -367,7 +360,6 @@ export const githubRouter = createTRPCRouter({
workspaceId: org.workspaceId,
organizationId: org.id,
repositoryName: d.repository.name,
- branch: org.branch,
})),
)
.returning();
@@ -394,7 +386,6 @@ export const githubRouter = createTRPCRouter({
description: d.description ?? "",
githubConfigFileId: insertedConfigFiles.find(
(icf) =>
- icf.name === cf.name &&
icf.path === cf.path &&
icf.repositoryName === cf.repository.name,
)?.id,
diff --git a/packages/db/src/schema/github.ts b/packages/db/src/schema/github.ts
index 68c0f009e..f3ab02fff 100644
--- a/packages/db/src/schema/github.ts
+++ b/packages/db/src/schema/github.ts
@@ -5,6 +5,7 @@ import {
pgTable,
text,
timestamp,
+ uniqueIndex,
uuid,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
@@ -45,19 +46,29 @@ export type GithubOrganization = InferSelectModel
;
export const githubOrganizationInsert = createInsertSchema(githubOrganization);
-export const githubConfigFile = pgTable("github_config_file", {
- id: uuid("id").primaryKey().defaultRandom(),
- organizationId: uuid("organization_id")
- .notNull()
- .references(() => githubOrganization.id, { onDelete: "cascade" }),
- repositoryName: text("repository_name").notNull(),
- branch: text("branch").notNull().default("main"),
- path: text("path").notNull(),
- name: text("name").notNull(),
- workspaceId: uuid("workspace_id")
- .notNull()
- .references(() => workspace.id, { onDelete: "cascade" }),
- lastSyncedAt: timestamp("last_synced_at", {
- withTimezone: true,
- }).defaultNow(),
-});
+export const githubConfigFile = pgTable(
+ "github_config_file",
+ {
+ id: uuid("id").primaryKey().defaultRandom(),
+ organizationId: uuid("organization_id")
+ .notNull()
+ .references(() => githubOrganization.id, { onDelete: "cascade" }),
+ repositoryName: text("repository_name").notNull(),
+ path: text("path").notNull(),
+ workspaceId: uuid("workspace_id")
+ .notNull()
+ .references(() => workspace.id, { onDelete: "cascade" }),
+ lastSyncedAt: timestamp("last_synced_at", {
+ withTimezone: true,
+ }).defaultNow(),
+ },
+ (t) => ({
+ unique: uniqueIndex("unique_organization_repository_path").on(
+ t.organizationId,
+ t.repositoryName,
+ t.path,
+ ),
+ }),
+);
+
+export type GithubConfigFile = InferSelectModel;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7a98e23cf..5b1864469 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -322,6 +322,12 @@ importers:
'@octokit/auth-app':
specifier: ^7.1.0
version: 7.1.0
+ '@octokit/rest':
+ specifier: ^20.1.1
+ version: 20.1.1
+ '@octokit/webhooks-types':
+ specifier: ^7.5.1
+ version: 7.5.1
'@opentelemetry/api-logs':
specifier: ^0.52.1
version: 0.52.1
@@ -2485,6 +2491,9 @@ packages:
'@octokit/types@13.5.0':
resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==}
+ '@octokit/webhooks-types@7.5.1':
+ resolution: {integrity: sha512-1dozxWEP8lKGbtEu7HkRbK1F/nIPuJXNfT0gd96y6d3LcHZTtRtlf8xz3nicSJfesADxJyDh+mWBOsdLkqgzYw==}
+
'@openapitools/openapi-generator-cli@2.13.5':
resolution: {integrity: sha512-9VgeKOTiiatKSwZDKKB3C86cW8tN9eDcFohotD4eisdK38UQswk/4Ysoq9KChRCbymjoMp6AIDHPtK1DQ2fTgw==}
engines: {node: '>=10.0.0'}
@@ -3799,83 +3808,83 @@ packages:
peerDependencies:
'@redis/client': ^1.0.0
- '@rollup/rollup-android-arm-eabi@4.21.0':
- resolution: {integrity: sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==}
+ '@rollup/rollup-android-arm-eabi@4.21.1':
+ resolution: {integrity: sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==}
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm64@4.21.0':
- resolution: {integrity: sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==}
+ '@rollup/rollup-android-arm64@4.21.1':
+ resolution: {integrity: sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==}
cpu: [arm64]
os: [android]
- '@rollup/rollup-darwin-arm64@4.21.0':
- resolution: {integrity: sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==}
+ '@rollup/rollup-darwin-arm64@4.21.1':
+ resolution: {integrity: sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==}
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.21.0':
- resolution: {integrity: sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==}
+ '@rollup/rollup-darwin-x64@4.21.1':
+ resolution: {integrity: sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==}
cpu: [x64]
os: [darwin]
- '@rollup/rollup-linux-arm-gnueabihf@4.21.0':
- resolution: {integrity: sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.21.1':
+ resolution: {integrity: sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.21.0':
- resolution: {integrity: sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==}
+ '@rollup/rollup-linux-arm-musleabihf@4.21.1':
+ resolution: {integrity: sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.21.0':
- resolution: {integrity: sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==}
+ '@rollup/rollup-linux-arm64-gnu@4.21.1':
+ resolution: {integrity: sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.21.0':
- resolution: {integrity: sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==}
+ '@rollup/rollup-linux-arm64-musl@4.21.1':
+ resolution: {integrity: sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-powerpc64le-gnu@4.21.0':
- resolution: {integrity: sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==}
+ '@rollup/rollup-linux-powerpc64le-gnu@4.21.1':
+ resolution: {integrity: sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.21.0':
- resolution: {integrity: sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==}
+ '@rollup/rollup-linux-riscv64-gnu@4.21.1':
+ resolution: {integrity: sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==}
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.21.0':
- resolution: {integrity: sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==}
+ '@rollup/rollup-linux-s390x-gnu@4.21.1':
+ resolution: {integrity: sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==}
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.21.0':
- resolution: {integrity: sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==}
+ '@rollup/rollup-linux-x64-gnu@4.21.1':
+ resolution: {integrity: sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.21.0':
- resolution: {integrity: sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==}
+ '@rollup/rollup-linux-x64-musl@4.21.1':
+ resolution: {integrity: sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-win32-arm64-msvc@4.21.0':
- resolution: {integrity: sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==}
+ '@rollup/rollup-win32-arm64-msvc@4.21.1':
+ resolution: {integrity: sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==}
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.21.0':
- resolution: {integrity: sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==}
+ '@rollup/rollup-win32-ia32-msvc@4.21.1':
+ resolution: {integrity: sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==}
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.21.0':
- resolution: {integrity: sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==}
+ '@rollup/rollup-win32-x64-msvc@4.21.1':
+ resolution: {integrity: sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==}
cpu: [x64]
os: [win32]
@@ -4714,8 +4723,8 @@ packages:
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'}
- cjs-module-lexer@1.3.1:
- resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==}
+ cjs-module-lexer@1.4.0:
+ resolution: {integrity: sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g==}
class-variance-authority@0.7.0:
resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==}
@@ -8014,8 +8023,8 @@ packages:
robust-predicates@3.0.2:
resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
- rollup@4.21.0:
- resolution: {integrity: sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==}
+ rollup@4.21.1:
+ resolution: {integrity: sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -10110,6 +10119,8 @@ snapshots:
dependencies:
'@octokit/openapi-types': 22.2.0
+ '@octokit/webhooks-types@7.5.1': {}
+
'@openapitools/openapi-generator-cli@2.13.5':
dependencies:
'@nestjs/axios': 3.0.2(@nestjs/common@10.3.0(reflect-metadata@0.1.13)(rxjs@7.8.1))(axios@1.7.4)(rxjs@7.8.1)
@@ -11877,52 +11888,52 @@ snapshots:
dependencies:
'@redis/client': 1.5.17
- '@rollup/rollup-android-arm-eabi@4.21.0':
+ '@rollup/rollup-android-arm-eabi@4.21.1':
optional: true
- '@rollup/rollup-android-arm64@4.21.0':
+ '@rollup/rollup-android-arm64@4.21.1':
optional: true
- '@rollup/rollup-darwin-arm64@4.21.0':
+ '@rollup/rollup-darwin-arm64@4.21.1':
optional: true
- '@rollup/rollup-darwin-x64@4.21.0':
+ '@rollup/rollup-darwin-x64@4.21.1':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.21.0':
+ '@rollup/rollup-linux-arm-gnueabihf@4.21.1':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.21.0':
+ '@rollup/rollup-linux-arm-musleabihf@4.21.1':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.21.0':
+ '@rollup/rollup-linux-arm64-gnu@4.21.1':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.21.0':
+ '@rollup/rollup-linux-arm64-musl@4.21.1':
optional: true
- '@rollup/rollup-linux-powerpc64le-gnu@4.21.0':
+ '@rollup/rollup-linux-powerpc64le-gnu@4.21.1':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.21.0':
+ '@rollup/rollup-linux-riscv64-gnu@4.21.1':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.21.0':
+ '@rollup/rollup-linux-s390x-gnu@4.21.1':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.21.0':
+ '@rollup/rollup-linux-x64-gnu@4.21.1':
optional: true
- '@rollup/rollup-linux-x64-musl@4.21.0':
+ '@rollup/rollup-linux-x64-musl@4.21.1':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.21.0':
+ '@rollup/rollup-win32-arm64-msvc@4.21.1':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.21.0':
+ '@rollup/rollup-win32-ia32-msvc@4.21.1':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.21.0':
+ '@rollup/rollup-win32-x64-msvc@4.21.1':
optional: true
'@swc/counter@0.1.3': {}
@@ -11930,7 +11941,7 @@ snapshots:
'@swc/helpers@0.5.5':
dependencies:
'@swc/counter': 0.1.3
- tslib: 2.6.3
+ tslib: 2.6.2
'@t3-oss/env-core@0.10.1(typescript@5.5.3)(zod@3.23.8)':
dependencies:
@@ -12986,7 +12997,7 @@ snapshots:
chownr@3.0.0: {}
- cjs-module-lexer@1.3.1: {}
+ cjs-module-lexer@1.4.0: {}
class-variance-authority@0.7.0:
dependencies:
@@ -14886,7 +14897,7 @@ snapshots:
dependencies:
acorn: 8.12.1
acorn-import-attributes: 1.9.5(acorn@8.12.1)
- cjs-module-lexer: 1.3.1
+ cjs-module-lexer: 1.4.0
module-details-from-path: 1.0.3
imurmurhash@0.1.4: {}
@@ -16428,7 +16439,7 @@ snapshots:
path-scurry@1.10.1:
dependencies:
lru-cache: 10.3.0
- minipass: 7.0.4
+ minipass: 7.1.2
path-to-regexp@0.1.7: {}
@@ -17160,26 +17171,26 @@ snapshots:
robust-predicates@3.0.2: {}
- rollup@4.21.0:
+ rollup@4.21.1:
dependencies:
'@types/estree': 1.0.5
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.21.0
- '@rollup/rollup-android-arm64': 4.21.0
- '@rollup/rollup-darwin-arm64': 4.21.0
- '@rollup/rollup-darwin-x64': 4.21.0
- '@rollup/rollup-linux-arm-gnueabihf': 4.21.0
- '@rollup/rollup-linux-arm-musleabihf': 4.21.0
- '@rollup/rollup-linux-arm64-gnu': 4.21.0
- '@rollup/rollup-linux-arm64-musl': 4.21.0
- '@rollup/rollup-linux-powerpc64le-gnu': 4.21.0
- '@rollup/rollup-linux-riscv64-gnu': 4.21.0
- '@rollup/rollup-linux-s390x-gnu': 4.21.0
- '@rollup/rollup-linux-x64-gnu': 4.21.0
- '@rollup/rollup-linux-x64-musl': 4.21.0
- '@rollup/rollup-win32-arm64-msvc': 4.21.0
- '@rollup/rollup-win32-ia32-msvc': 4.21.0
- '@rollup/rollup-win32-x64-msvc': 4.21.0
+ '@rollup/rollup-android-arm-eabi': 4.21.1
+ '@rollup/rollup-android-arm64': 4.21.1
+ '@rollup/rollup-darwin-arm64': 4.21.1
+ '@rollup/rollup-darwin-x64': 4.21.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.21.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.21.1
+ '@rollup/rollup-linux-arm64-gnu': 4.21.1
+ '@rollup/rollup-linux-arm64-musl': 4.21.1
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.21.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.21.1
+ '@rollup/rollup-linux-s390x-gnu': 4.21.1
+ '@rollup/rollup-linux-x64-gnu': 4.21.1
+ '@rollup/rollup-linux-x64-musl': 4.21.1
+ '@rollup/rollup-win32-arm64-msvc': 4.21.1
+ '@rollup/rollup-win32-ia32-msvc': 4.21.1
+ '@rollup/rollup-win32-x64-msvc': 4.21.1
fsevents: 2.3.3
rtl-css-js@1.16.1:
@@ -17834,7 +17845,7 @@ snapshots:
picocolors: 1.0.1
postcss-load-config: 6.0.1(jiti@1.21.6)(postcss@8.4.39)(tsx@4.16.2)
resolve-from: 5.0.0
- rollup: 4.21.0
+ rollup: 4.21.1
source-map: 0.8.0-beta.0
sucrase: 3.35.0
tree-kill: 1.2.2