ad137fbf9c
* ci(companion): add separate typecheck workflow to catch type errors This adds a new companion-typecheck.yml workflow that runs TypeScript type checking for the companion app. This would have caught the missing useEffect import issue in PR #26931. Changes: - Add new companion-typecheck.yml workflow file - Update pr.yml to call the new workflow when companion files change - Add typecheck-companion to the required jobs list Co-Authored-By: anik@cal.com <adhabal2002@gmail.com> * add lint checks * test * remove * update typecheck * address review * chore:- hide apps with missing required keys from app store * update * Delete packages/app-store/_utils/hasRequiredAppKeys.test.ts * Update validateAppKeys.ts * Update validateAppKeys.ts * Update validateAppKeys.test.ts --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";
|
|
import type { NextRequest } from "next/server";
|
|
import { NextResponse } from "next/server";
|
|
|
|
import { getAppWithMetadata } from "@calcom/app-store/_appRegistry";
|
|
import { shouldEnableApp } from "@calcom/app-store/_utils/validateAppKeys";
|
|
import logger from "@calcom/lib/logger";
|
|
import { prisma } from "@calcom/prisma";
|
|
import type { AppCategories, Prisma } from "@calcom/prisma/client";
|
|
|
|
const isDryRun = process.env.CRON_ENABLE_APP_SYNC !== "true";
|
|
const log = logger.getSubLogger({
|
|
prefix: ["[api/cron/syncAppMeta]", ...(isDryRun ? ["(dry-run)"] : [])],
|
|
});
|
|
|
|
/**
|
|
* syncAppMeta makes sure any app metadata that has been replicated into the database
|
|
* remains synchronized with any changes made to the app config files.
|
|
*/
|
|
async function postHandler(request: NextRequest) {
|
|
const apiKey = request.headers.get("authorization") || request.nextUrl.searchParams.get("apiKey");
|
|
|
|
if (process.env.CRON_API_KEY !== apiKey) {
|
|
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
|
}
|
|
|
|
log.info(`🧐 Checking DB apps are in-sync with app metadata`);
|
|
|
|
const dbApps = await prisma.app.findMany();
|
|
|
|
for await (const dbApp of dbApps) {
|
|
const app = await getAppWithMetadata(dbApp);
|
|
const updates: Prisma.AppUpdateManyMutationInput = {};
|
|
|
|
if (!app) {
|
|
log.warn(`💀 App ${dbApp.slug} (${dbApp.dirName}) no longer exists.`);
|
|
continue;
|
|
}
|
|
|
|
// Check for any changes in the app categories (tolerates changes in ordering)
|
|
if (
|
|
dbApp.categories.length !== app.categories.length ||
|
|
!dbApp.categories.every((category) => app.categories.includes(category))
|
|
) {
|
|
updates["categories"] = app.categories as AppCategories[];
|
|
}
|
|
|
|
if (dbApp.dirName !== (app.dirName ?? app.slug)) {
|
|
updates["dirName"] = app.dirName ?? app.slug;
|
|
}
|
|
|
|
// Ensure app is only enabled if it has valid keys (or doesn't require keys)
|
|
const shouldBeEnabled = shouldEnableApp(dbApp.dirName, dbApp.keys);
|
|
if (dbApp.enabled !== shouldBeEnabled) {
|
|
updates["enabled"] = shouldBeEnabled;
|
|
if (!shouldBeEnabled && dbApp.enabled) {
|
|
log.warn(
|
|
`⚠️ Disabling app ${dbApp.slug} - required keys are missing or invalid. Please configure keys in admin settings.`
|
|
);
|
|
}
|
|
}
|
|
|
|
if (Object.keys(updates).length > 0) {
|
|
log.info(`🔨 Updating app ${dbApp.slug} with ${Object.keys(updates).join(", ")}`);
|
|
if (!isDryRun) {
|
|
await prisma.app.update({
|
|
where: { slug: dbApp.slug },
|
|
data: updates,
|
|
});
|
|
}
|
|
} else {
|
|
log.info(`✅ App ${dbApp.slug} is up-to-date and correct`);
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({ ok: true });
|
|
}
|
|
|
|
export const POST = defaultResponderForAppDir(postHandler);
|