cf-api fix (#1512)

### **PR Type**
- Enhancement
- Bug fix



___

### **Description**
- Update ES module import paths with explicit .js extensions.

- Refactor function signatures and type annotations for TypeScript.

- Wrap Express app with @awaitjs/express for async support.

- Upgrade package configurations and tsconfig settings.


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>6
files</summary><table>
<tr>
<td><strong>diff_utils.test.ts</strong><dd><code>Adjust import paths to
include .js extensions.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-c0991313f3fcb63fa2a553856b85d7df03e6d99cf98d19277fe689025f89ede1">+2/-2</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>create-pr-from-diffcontents.ts</strong><dd><code>Update
import paths and adjust Octokit typing.</code>&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-b30d5e0c89beb70c0333a025726867aba5db7614911be3c46664bb59d1ab594a">+12/-11</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>index.ts</strong><dd><code>Use @awaitjs/express wrap to
create AsyncExpressApp.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-c3e60be1461b6e80f9181080342927fd9df095197e8784ae0ff51daaec8d71d5">+7/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>setupAction.ts</strong><dd><code>Update workflow setup
action and adjust GitHub API usage.</code></dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-88c84a935a854855fb103dbf560f6ed5ea2e73e45750c97b5a3b901a5f9399a2">+5/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>types.d.ts</strong><dd><code>Add new type definitions for
Octokit and AsyncExpressApp.</code></dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-370b1e96082f265e191b7aac76caa9feb60d32d56c36a2924725200b3d41f423">+45/-0</a>&nbsp;
&nbsp; </td>

</tr>

<tr>
<td><strong>types.ts</strong><dd><code>Remove obsolete types; migrate to
types.d.ts.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-8d1257d2e60e56e9c02c59b85078e89ad41af60267b02842daf203da3231902f">+0/-6</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Bug
fix</strong></td><td><details><summary>4 files</summary><table>
<tr>
<td><strong>is-github-app-installed.ts</strong><dd><code>Add ts-ignore
and adjust GitHub app installation endpoint.</code></dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-4b97bd2b461108930999b4af7e47d4763ad1b9490f7352130109c39f5abf4561">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>suggest-pr-changes.ts</strong><dd><code>Refactor types, cast
Octokit instance, and update parameters.</code></dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-b4a862986fd70827b8dabcb3157972bd0d5d507cf9c12e5fbf56f24979d073f3">+22/-15</a>&nbsp;
</td>

</tr>

<tr>
<td><strong>check-valid-api-key.ts</strong><dd><code>Refine middleware
typing with NextFunction.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-c04a6087bbabce916c7547acf14c186caf7af3ec6ff68b7e49102c3fe87e453c">+9/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>track-usage.ts</strong><dd><code>Change Request type to
AuthorizedUserReq in usage tracker.</code></dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-9248228a33147544ca9b58ff8b9c737b33763dd3e29717c82c38808bb7e34db3">+2/-1</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Configuration
changes</strong></td><td><details><summary>2 files</summary><table>
<tr>
<td><strong>package.json</strong><dd><code>Upgrade dependencies and
refine build/deploy scripts.</code>&nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-53ddfb1f8a02f1231d3d15a2e694ffe1407d2cc01d3e685de5653b67fec571c7">+8/-3</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

<tr>
<td><strong>tsconfig.json</strong><dd><code>Modify module, strict, and
lib options for NodeNext.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-3532a852c82c88daeed6b57a35cd52c4a2589c909edc756613d67e280ab9b23e">+6/-5</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>

</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1
files</summary><table>
<tr>
<td><strong>migration.sql</strong><dd><code>Add placeholder migration
for rolled back changes.</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></td>
<td><a
href="https://github.com/codeflash-ai/codeflash-internal/pull/1512/files#diff-98f5513f409a695839ec0bb0ee8e77d3c858e26c30db2113a83973dc1fa46c25">+1/-0</a>&nbsp;
&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr></tr></tbody></table>

___

> <details> <summary> Need help?</summary><li>Type <code>/help how to
...</code> in the comments thread for any questions about PR-Agent
usage.</li><li>Check out the <a
href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a>
for more information.</li></details>
This commit is contained in:
Sarthak Agarwal 2025-03-13 04:00:10 +05:30 committed by dasarchan
parent 5d10f1cdb8
commit 5d85db581c
15 changed files with 359 additions and 884 deletions

View file

@ -7,3 +7,4 @@ node_modules
.sentryclirc
/.npmrc
/.azure/config
/dist/*

View file

@ -1,5 +1,5 @@
import { fileDiffsToMap, isDiffContentsWellFormed } from "./diff_utils"
import { type FileDiffContent } from "code-suggester/build/src/types"
import { fileDiffsToMap, isDiffContentsWellFormed } from "./diff_utils.js"
import { type FileDiffContent } from "code-suggester/build/src/types.js"
describe("fileDiffsToMap", () => {
it("should correctly convert an object to a Map", () => {

View file

@ -2,6 +2,7 @@ import { userNickname } from "../auth0-mgmt.js"
import { getInstallationOctokitByOwner, isUserCollaborator } from "../github/github-utils.js"
import { githubApp } from "../github/github-app.js"
// @ts-ignore
export async function isGitHubAppInstalled(req, res): Promise<void> {
const { owner, repo } = req.query
if (!owner || !repo) {

View file

@ -1,19 +1,20 @@
import { determineValidHunks, fileDiffsToMap, isDiffContentsWellFormed } from "../diff_utils"
import { userNickname } from "../auth0-mgmt"
import { getInstallationOctokitByOwner, isUserCollaborator } from "../github/github-utils"
import { githubApp } from "../github/github-app"
import { buildDependentPrTitle } from "../github/pr-changes-utils"
import { determineValidHunks, fileDiffsToMap, isDiffContentsWellFormed } from "../diff_utils.js"
import { userNickname } from "../auth0-mgmt.js"
import { getInstallationOctokitByOwner, isUserCollaborator } from "../github/github-utils.js"
import { githubApp } from "../github/github-app.js"
import { buildDependentPrTitle } from "../github/pr-changes-utils.js"
import {
createDependentPullRequest,
createNewBranchFromDiffContents,
} from "../github/create-pr-from-diffcontents"
import { buildPrCommentBody } from "../github/pr-changes-utils"
import { posthog } from "../analytics"
} from "../github/create-pr-from-diffcontents.js"
import { buildPrCommentBody } from "../github/pr-changes-utils.js"
import { posthog } from "../analytics.js"
import suggester from "code-suggester"
import { type FileDiffContent } from "code-suggester/build/src/types.js"
import { PrismaClient } from "@prisma/client"
import { sendSlackMessage } from "../github/slack_util"
import { sendSlackMessage } from "../github/slack_util.js"
import { Request, Response } from "express"
import { AnyOctokit, AuthorizedUserReq, PullRequestDB } from "../types.js"
interface CustomRequest extends Request {
userId?: string
@ -26,7 +27,10 @@ const slackNotificationConfig = {
"albumentations-team": ["albumentations"],
}
export async function suggestPrChanges(req: Request, res: Response): Promise<Response | undefined> {
export async function suggestPrChanges(
req: AuthorizedUserReq,
res: Response,
): Promise<Response | undefined> {
try {
const {
owner,
@ -68,7 +72,7 @@ export async function suggestPrChanges(req: Request, res: Response): Promise<Res
const diffContentsMap: Map<string, FileDiffContent> = fileDiffsToMap(diffContents)
const { validHunks, invalidHunks } = await determineValidHunks(
installationOctokit.rest,
installationOctokit as AnyOctokit,
{ owner, repo },
pullNumber,
100,
@ -123,7 +127,7 @@ export async function suggestPrChanges(req: Request, res: Response): Promise<Res
console.log(`Making a new dependent PR...`)
const newPrData = await createDependentPullRequest(
installationOctokit,
installationOctokit as AnyOctokit,
owner,
repo,
pullNumber,
@ -132,6 +136,7 @@ export async function suggestPrChanges(req: Request, res: Response): Promise<Res
prCommentFields,
existingTests,
generatedTests,
"",
)
// Respond with the new PR details
@ -169,7 +174,8 @@ export async function suggestPrChanges(req: Request, res: Response): Promise<Res
if (pull_request_db.pull_request === null || pull_request_db.pull_request === undefined) {
pull_request_db.pull_request = {}
}
pull_request_db.pull_request.dependent_pr_url = newPrData.data.html_url
;(pull_request_db as PullRequestDB).pull_request.dependent_pr_url =
newPrData.data.html_url
await prisma.optimization_features.update({
where: {
@ -188,7 +194,7 @@ export async function suggestPrChanges(req: Request, res: Response): Promise<Res
console.log(`Making suggestions...`)
const reviewNumber = await suggester.reviewPullRequest(
installationOctokit.rest,
installationOctokit as AnyOctokit,
diffContentsMap,
{
repo,
@ -255,7 +261,8 @@ export async function suggestPrChanges(req: Request, res: Response): Promise<Res
pull_request_db.pull_request = {}
}
pull_request_db.pull_request.review_suggestion_pr_url = result.data.html_url
;(pull_request_db as PullRequestDB).pull_request.review_suggestion_pr_url =
result.data.html_url
await prisma.optimization_features.update({
where: {

View file

@ -1,9 +1,10 @@
import { type FileDiffContent } from "code-suggester/build/src/types"
import { type FileDiffContent } from "code-suggester/build/src/types.js"
import { type Octokit } from "octokit"
import { addLabelToPullRequest } from "./github-utils"
import { buildDependentPrTitle, buildPrTitle, buildResultFooter } from "./pr-changes-utils"
import { addLabelToPullRequest } from "./github-utils.js"
import { buildDependentPrTitle, buildPrTitle, buildResultFooter } from "./pr-changes-utils.js"
import type { RestEndpointMethodTypes } from "@octokit/rest"
import { buildResultHeader, buildResultDetails, buildResultTestReport } from "./pr-changes-utils"
import { buildResultHeader, buildResultDetails, buildResultTestReport } from "./pr-changes-utils.js"
import { AnyOctokit, PullRequestCreationResponse } from "../types.js"
type PullsCreateResponse = RestEndpointMethodTypes["pulls"]["create"]["response"]
type GitCreateTreeParamsTree =
@ -110,7 +111,7 @@ export async function createNewBranchFromDiffContents(
}
async function createNewPullRequest(
installationOctokit: Octokit,
installationOctokit: AnyOctokit,
owner: string,
repo: string,
title: string,
@ -118,7 +119,7 @@ async function createNewPullRequest(
newBranchName: string,
baseBranch: string,
// ): Promise<Octokit.Response<Octokit.PullsCreateResponse>> {
): Promise<PullsCreateResponse> {
): Promise<PullRequestCreationResponse> {
return await installationOctokit.rest.pulls.create({
owner,
repo,
@ -145,7 +146,7 @@ export async function assignReviewer(
}
export async function createStandalonePullRequest(
installationOctokit: Octokit,
installationOctokit: AnyOctokit,
owner: string,
repo: string,
newBranchName: string,
@ -154,7 +155,7 @@ export async function createStandalonePullRequest(
existingTests: string,
generatedTests: string,
coverage_message: string,
): Promise<Response<PullsCreateResponse>> {
): Promise<PullRequestCreationResponse> {
// Open a new standalone Codeflash PR (that doesn't reference an original PR, likely just to main)
const prCommentHeader = buildResultHeader(prCommentFields)
// Open a new PR from the new branch onto the original PR's head branch
@ -189,7 +190,7 @@ export async function createStandalonePullRequest(
}
export async function createDependentPullRequest(
installationOctokit: Octokit,
installationOctokit: AnyOctokit,
owner: string,
repo: string,
origPrNumber: number,
@ -199,7 +200,7 @@ export async function createDependentPullRequest(
existingTests: string,
generatedTests: string,
coverage_message: string,
): Promise<Response<PullsCreateResponse>> {
): Promise<PullRequestCreationResponse> {
const prCommentHeader = buildResultHeader(prCommentFields)
// Open a new PR from the new branch onto the original PR's head branch
const prCommentBody = buildResultDetails(prCommentFields)
@ -245,7 +246,7 @@ If you approve this dependent PR, these changes will be merged into the original
issue_number: origPrNumber,
body: `## ⚡️ Codeflash found optimizations for this PR
${prCommentHeader}
#### I created a new dependent PR with the suggested changes. Please review:
#### I created a new dependent PR with the suggested changes. Please review:
- ### #${newPrData.data.number}

View file

@ -5,7 +5,8 @@ import "./instrument"
import express from "express"
import cors from "cors"
import { ghAppMiddleware, ghAppPathPrefix } from "./github/github-app.js"
import { wrap } from "@awaitjs/express"
import { AsyncExpressApp } from "./types.js"
import * as console from "console"
import { posthog } from "./analytics.js"
import { suggestPrChanges } from "./endpoints/suggest-pr-changes.js"
@ -24,8 +25,9 @@ import { stripeWebhookHandler } from "./endpoints/stripe-webhook.js"
import { trackUsage } from "./middlewares/track-usage.js"
const port = process.env.PORT ?? 3001
const appExpress = addAsync(express())
// Define a custom type for the wrapped Express app
const app = express()
const appExpress = wrap(app) as any as AsyncExpressApp
// ToDO:The request handler must be the first middleware on the app
// appExpress.use(
@ -90,7 +92,7 @@ const optimizationEndpoints = [
]
// Apply usage tracking to optimization endpoints
optimizationEndpoints.forEach((endpoint) => {
optimizationEndpoints.forEach(endpoint => {
appExpress.use(endpoint, trackUsage)
})
@ -123,7 +125,7 @@ appExpress.postAsync("/cfapi/cancel-subscription", cancelSubscription)
Sentry.setupExpressErrorHandler(appExpress)
// Start the server
appExpress.listen(port, () => {
appExpress.listen(Number(port), () => {
console.log(
`Server is listening on ${port} for CF API requests. Github App webhook events mounted at ${ghAppPathPrefix}`,
)

View file

@ -1,8 +1,14 @@
import { posthog } from "../analytics"
import { posthog } from "../analytics.js"
import { userForAPIKey } from "@codeflash-ai/common"
import { AuthorizedUserReq } from "../types.js"
import { NextFunction } from "express"
import { Response } from "express"
// Middleware to check for valid API key
export async function checkForValidAPIKey(req: AuthorizedUserReq, res: Response, next: () => void) {
export async function checkForValidAPIKey(
req: AuthorizedUserReq,
res: Response,
next: NextFunction,
) {
const authHeader = req.headers.authorization
if (authHeader == null) {
posthog.capture({

View file

@ -1,8 +1,9 @@
import { Request, Response, NextFunction } from "express"
import { prisma } from "@codeflash-ai/common"
import * as Sentry from "@sentry/node"
import { AuthorizedUserReq } from "../types.js"
export async function trackUsage(req: Request, res: Response, next: NextFunction) {
export async function trackUsage(req: AuthorizedUserReq, res: Response, next: NextFunction) {
//ToDO: Sarthak: resolve errors for tslint
const userId = req.userId // Get userId from the request object (set by checkForValidAPIKey)

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,8 @@
"type": "module",
"scripts": {
"npx": "npx",
"build": "npm install --loglevel verbose && npx prisma generate",
"deploy": "az webapp up -n codeflash-api --sku P1V2 --runtime NODE:20-lts",
"build": "npm install --loglevel verbose && npx prisma generate && tsc",
"deploy": "az webapp up -n codeflash-api --sku P1V2 --runtime NODE:20-lts --verbose",
"start": "npx prisma generate && npx tsx index.ts",
"prisma:generate": "cd ../common && npx prisma generate",
"prisma:migrate": "cd ../common && npx prisma migrate dev",
@ -25,6 +25,11 @@
"@azure/keyvault-secrets": "^4.7.0",
"@codeflash-ai/common": "1.0.10",
"@notionhq/client": "^2.2.14",
"@octokit/app": "^15.1.5",
"@octokit/auth-app": "^7.1.5",
"@octokit/core": "^6.1.4",
"@octokit/plugin-rest-endpoint-methods": "^13.3.1",
"@octokit/rest": "^19.0.13",
"@prisma/client": "^6.2.1",
"@sentry/node": "^8.7.0",
"@sentry/profiling-node": "^8.7.0",
@ -38,7 +43,7 @@
"express": "^4.19.2",
"http": "^0.0.1-security",
"node-fetch": "^3.3.2",
"octokit": "^4.0.2",
"octokit": "^4.1.2",
"posthog-node": "^4.0.0",
"stripe": "^17.7.0",
"tsx": "^4.1.4"

View file

@ -1,4 +1,5 @@
import fs from "fs"
import { AnyOctokit } from "./types.js"
const APP_ID: string = process.env.APP_ID || "" // Replace with your GitHub App ID
@ -27,11 +28,12 @@ jobs:
- uses: actions/checkout@v4
- uses: Codeflash/optimize-action@main
with:
token:
token:
`,
).toString("base64")
await installationOctokit.repos.createOrUpdateFileContents({
let installationOctokit: AnyOctokit
await installationOctokit.rest.repos.createOrUpdateFileContents({
owner: repoOwner,
repo: repoName,
path: ".github/workflows/optimize.yml",
@ -41,4 +43,4 @@ jobs:
}
// Example usage
createWorkflow("user-or-org", "repo-name", 123456) // Replace with actual owner, repo name, and installation ID
createWorkflow("user-or-org", "repo-name") // Replace with actual owner, repo name, and installation ID

View file

@ -2,18 +2,19 @@
"compilerOptions": {
"esModuleInterop": true,
"lib": ["es2020"],
"module": "node16",
"module": "NodeNext",
"preserveConstEnums": true,
"moduleResolution": "node16",
"strict": true,
"strictNullChecks": true,
"moduleResolution": "NodeNext",
"strict": false,
"strictNullChecks": false,
"sourceMap": true,
"target": "es2022",
"types": ["node", "jest", "express"],
"outDir": "dist",
"baseUrl": ".",
"skipLibCheck": true,
"paths": {}
},
"include": ["src/**/*", "**/*.ts", "*.ts"],
"include": ["src/**/*", "**/*.ts", "*.ts", "types.d.ts"],
"exclude": ["node_modules"]
}

45
js/cf-api/types.d.ts vendored Normal file
View file

@ -0,0 +1,45 @@
import { Request } from "express"
// Permissive Octokit type
export type AnyOctokit = any
// PR response type
export type PullRequestCreationResponse = any
// Extended Request with userId
export interface AuthorizedUserReq extends Request {
userId?: string
user?: {
id: string
email?: string
}
}
// PR database interface
export interface PullRequestDB {
pull_request: {
dependent_pr_url?: string
review_suggestion_pr_url?: string
[key: string]: any
}
}
// Complete AsyncExpressApp interface
export interface AsyncExpressApp {
post(path: string, handler: any): AsyncExpressApp
post(path: string, middleware: any, handler: any): AsyncExpressApp
post(path: string, ...handlers: any[]): AsyncExpressApp
// Async methods
postAsync: (path: string, handler: (req: any, res: any, next?: any) => Promise<any>) => void
getAsync: (path: string, handler: (req: any, res: any, next?: any) => Promise<any>) => void
// Standard Express methods
use: (pathOrMiddleware: any, middleware?: any) => AsyncExpressApp
get: (path: string, handler: (req: any, res: any, next?: any) => any) => AsyncExpressApp
post: (path: string, handler: (req: any, res: any, next?: any) => any) => AsyncExpressApp
put: (path: string, handler: (req: any, res: any, next?: any) => any) => AsyncExpressApp
delete: (path: string, handler: (req: any, res: any, next?: any) => any) => AsyncExpressApp
patch: (path: string, handler: (req: any, res: any, next?: any) => any) => AsyncExpressApp
listen: (port: number, callback?: () => void) => any
}

View file

@ -1,6 +0,0 @@
interface AuthorizedUserReq {
headers: { authorization: any }
url: any
body: any
userId: any
}

View file

@ -0,0 +1 @@
-- This is a placeholder for a failed migration that was rolled back