Skip to content

Commit 4537cac

Browse files
committed
feat(vercel): PR feedback changes
1 parent 13489c6 commit 4537cac

17 files changed

+136
-183
lines changed

apps/webapp/app/components/integrations/VercelOnboardingModal.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,6 @@ export function VercelOnboardingModal({
320320
if (state === "project-selection" && fetcher.data && "success" in fetcher.data && fetcher.data.success && fetcher.state === "idle") {
321321
setState("loading-env-mapping");
322322
if (onDataReload) {
323-
console.log("Vercel onboarding: Reloading data after successful project selection to get updated project info and env vars");
324323
onDataReload();
325324
}
326325
} else if (fetcher.data && "error" in fetcher.data && typeof fetcher.data.error === "string") {

apps/webapp/app/models/vercelIntegration.server.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Vercel } from "@vercel/sdk";
22
import {
3-
IntegrationService,
43
Organization,
54
OrganizationIntegration,
65
SecretReference,
@@ -34,7 +33,7 @@ function extractEnvs(response: unknown): unknown[] {
3433
}
3534

3635
function isVercelSecretType(type: string): boolean {
37-
return type === "secret" || type === "sensitive";
36+
return type === "secret" || type === "sensitive" || type === "encrypted";
3837
}
3938

4039
function vercelApiError(message: string, context: Record<string, unknown>, error: unknown): VercelAPIResult<never> {

apps/webapp/app/presenters/v3/BranchesPresenter.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export type GitMetaLinks = {
4242
/** The git provider, e.g., `github` */
4343
provider?: string;
4444

45-
source?: "trigger_github_app" | "github_actions" | "local" | "trigger_vercel_app";
45+
source?: "trigger_github_app" | "github_actions" | "local";
4646
ghUsername?: string;
4747
ghUserAvatarUrl?: string;
4848
};

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.settings/route.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
VercelOnboardingModal,
5151
vercelResourcePath,
5252
} from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.vercel";
53+
import type { loader as vercelLoader } from "../resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.vercel";
5354
import { OrgIntegrationRepository } from "~/models/orgIntegration.server";
5455
import { useTypedFetcher } from "remix-typedjson";
5556

@@ -312,7 +313,7 @@ export default function Page() {
312313
const hasQueryParam = searchParams.get("vercelOnboarding") === "true";
313314
const nextUrl = searchParams.get("next");
314315
const [isModalOpen, setIsModalOpen] = useState(false);
315-
const vercelFetcher = useTypedFetcher<any>();
316+
const vercelFetcher = useTypedFetcher<typeof vercelLoader>();
316317

317318
// Helper to open modal and ensure query param is present
318319
const openVercelOnboarding = useCallback(() => {

apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.integrations.vercel.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
LoaderFunctionArgs,
44
} from "@remix-run/node";
55
import { json, redirect } from "@remix-run/node";
6-
import { Form, useActionData, useLoaderData, useNavigation } from "@remix-run/react";
6+
import { Form, useActionData, useNavigation } from "@remix-run/react";
77
import { typedjson, useTypedLoaderData } from "remix-typedjson";
88
import { z } from "zod";
99
import { DialogClose } from "@radix-ui/react-dialog";
@@ -20,7 +20,7 @@ import { FormButtons } from "~/components/primitives/FormButtons";
2020
import { Header1 } from "~/components/primitives/Headers";
2121
import { PageBody, PageContainer } from "~/components/layout/AppLayout";
2222
import { Paragraph } from "~/components/primitives/Paragraph";
23-
import { Table, TableBlankRow, TableBody, TableCell, TableHeader, TableHeaderCell, TableRow } from "~/components/primitives/Table";
23+
import { Table, TableBody, TableCell, TableHeader, TableHeaderCell, TableRow } from "~/components/primitives/Table";
2424
import { VercelIntegrationRepository } from "~/models/vercelIntegration.server";
2525
import { $transaction, prisma } from "~/db.server";
2626
import { requireOrganization } from "~/services/org.server";
@@ -123,6 +123,11 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
123123
const { organizationSlug } = OrganizationParamsSchema.parse(params);
124124
const { organization, userId } = await requireOrganization(request, organizationSlug);
125125

126+
const formData = await request.formData();
127+
const result = ActionSchema.safeParse({ intent: formData.get("intent") });
128+
if (!result.success) {
129+
return json({ error: "Invalid action" }, { status: 400 });
130+
}
126131

127132
// Find Vercel integration
128133
const vercelIntegration = await prisma.organizationIntegration.findFirst({
@@ -347,11 +352,6 @@ export default function VercelIntegrationPage() {
347352
</TableCell>
348353
</TableRow>
349354
))}
350-
{connectedProjects.length === 0 && (
351-
<TableBlankRow colSpan={4}>
352-
<Paragraph>No connected projects found.</Paragraph>
353-
</TableBlankRow>
354-
)}
355355
</TableBody>
356356
</Table>
357357
)}

apps/webapp/app/routes/api.v1.orgs.$organizationSlug.projects.$projectParam.vercel.projects.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ import { z } from "zod";
44
import { prisma } from "~/db.server";
55
import { apiCors } from "~/utils/apiCors";
66
import { logger } from "~/services/logger.server";
7+
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
78
import { VercelIntegrationService } from "~/services/vercelIntegration.server";
8-
import {
9-
VercelProjectIntegrationDataSchema,
10-
} from "~/v3/vercel/vercelProjectIntegrationSchema";
119

1210
const ParamsSchema = z.object({
1311
organizationSlug: z.string(),
@@ -30,6 +28,15 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
3028
return apiCors(request, json({}));
3129
}
3230

31+
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
32+
33+
if (!authenticationResult) {
34+
return apiCors(
35+
request,
36+
json({ error: "Invalid or Missing Access Token" }, { status: 401 })
37+
);
38+
}
39+
3340
const parsedParams = ParamsSchema.safeParse(params);
3441
if (!parsedParams.success) {
3542
return apiCors(
@@ -41,12 +48,17 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
4148
const { organizationSlug, projectParam } = parsedParams.data;
4249

4350
try {
44-
// Find the project
51+
// Find the project, verifying org membership
4552
const project = await prisma.project.findFirst({
4653
where: {
4754
slug: projectParam,
4855
organization: {
4956
slug: organizationSlug,
57+
members: {
58+
some: {
59+
userId: authenticationResult.userId,
60+
},
61+
},
5062
},
5163
deletedAt: null,
5264
},

apps/webapp/app/routes/auth.github.callback.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { getSession, redirectWithErrorMessage } from "~/models/message.server";
55
import { authenticator } from "~/services/auth.server";
66
import { setLastAuthMethodHeader } from "~/services/lastAuthMethod.server";
77
import { commitSession } from "~/services/sessionStorage.server";
8-
import { getReferralSource, clearReferralSourceCookie } from "~/services/referralSource.server";
9-
import { telemetry } from "~/services/telemetry.server";
8+
import { trackAndClearReferralSource } from "~/services/referralSource.server";
109
import { redirectCookie } from "./auth.github";
1110
import { sanitizeRedirectPath } from "~/utils";
1211

@@ -56,25 +55,7 @@ export let loader: LoaderFunction = async ({ request }) => {
5655
headers.append("Set-Cookie", await commitSession(session));
5756
headers.append("Set-Cookie", await setLastAuthMethodHeader("github"));
5857

59-
const referralSource = await getReferralSource(request);
60-
if (referralSource) {
61-
const user = await prisma.user.findUnique({
62-
where: { id: auth.userId },
63-
});
64-
if (user) {
65-
const userAge = Date.now() - user.createdAt.getTime();
66-
const isNewUser = userAge < 30 * 1000;
67-
68-
if (isNewUser) {
69-
telemetry.user.identify({
70-
user,
71-
isNewUser: true,
72-
referralSource,
73-
});
74-
}
75-
}
76-
headers.append("Set-Cookie", await clearReferralSourceCookie());
77-
}
58+
await trackAndClearReferralSource(request, auth.userId, headers);
7859

7960
return redirect(redirectTo, { headers });
8061
};

apps/webapp/app/routes/auth.google.callback.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { getSession, redirectWithErrorMessage } from "~/models/message.server";
55
import { authenticator } from "~/services/auth.server";
66
import { setLastAuthMethodHeader } from "~/services/lastAuthMethod.server";
77
import { commitSession } from "~/services/sessionStorage.server";
8-
import { getReferralSource, clearReferralSourceCookie } from "~/services/referralSource.server";
9-
import { telemetry } from "~/services/telemetry.server";
8+
import { trackAndClearReferralSource } from "~/services/referralSource.server";
109
import { redirectCookie } from "./auth.google";
1110
import { sanitizeRedirectPath } from "~/utils";
1211

@@ -56,25 +55,7 @@ export let loader: LoaderFunction = async ({ request }) => {
5655
headers.append("Set-Cookie", await commitSession(session));
5756
headers.append("Set-Cookie", await setLastAuthMethodHeader("google"));
5857

59-
const referralSource = await getReferralSource(request);
60-
if (referralSource) {
61-
const user = await prisma.user.findUnique({
62-
where: { id: auth.userId },
63-
});
64-
if (user) {
65-
const userAge = Date.now() - user.createdAt.getTime();
66-
const isNewUser = userAge < 30 * 1000;
67-
68-
if (isNewUser) {
69-
telemetry.user.identify({
70-
user,
71-
isNewUser: true,
72-
referralSource,
73-
});
74-
}
75-
}
76-
headers.append("Set-Cookie", await clearReferralSourceCookie());
77-
}
58+
await trackAndClearReferralSource(request, auth.userId, headers);
7859

7960
return redirect(redirectTo, { headers });
8061
};

apps/webapp/app/routes/login.mfa/route.tsx

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ import { MultiFactorAuthenticationService } from "~/services/mfa/multiFactorAuth
2626
import { redirectWithErrorMessage, redirectBackWithErrorMessage } from "~/models/message.server";
2727
import { ServiceValidationError } from "~/v3/services/baseService.server";
2828
import { checkMfaRateLimit, MfaRateLimitError } from "~/services/mfa/mfaRateLimiter.server";
29-
import { getReferralSource, clearReferralSourceCookie } from "~/services/referralSource.server";
30-
import { telemetry } from "~/services/telemetry.server";
31-
import { prisma } from "~/db.server";
29+
import { trackAndClearReferralSource } from "~/services/referralSource.server";
3230

3331
export const meta: MetaFunction = ({ matches }) => {
3432
const parentMeta = matches
@@ -165,29 +163,9 @@ async function completeLogin(request: Request, session: Session, userId: string)
165163

166164
const headers = new Headers();
167165
headers.append("Set-Cookie", await sessionStorage.commitSession(authSession));
166+
headers.append("Set-Cookie", await commitSession(session));
168167

169-
// Read referral source cookie and set in PostHog if present (only for new users), then clear it
170-
const referralSource = await getReferralSource(request);
171-
if (referralSource) {
172-
const user = await prisma.user.findUnique({
173-
where: { id: userId },
174-
});
175-
if (user) {
176-
// Only set referralSource for new users (created within the last 30 seconds)
177-
const userAge = Date.now() - user.createdAt.getTime();
178-
const isNewUser = userAge < 30 * 1000; // 30 seconds
179-
180-
if (isNewUser) {
181-
telemetry.user.identify({
182-
user,
183-
isNewUser: true,
184-
referralSource,
185-
});
186-
}
187-
}
188-
// Clear the cookie after using it (regardless of whether we set it)
189-
headers.append("Set-Cookie", await clearReferralSourceCookie());
190-
}
168+
await trackAndClearReferralSource(request, userId, headers);
191169

192170
return redirect(redirectTo, { headers });
193171
}

apps/webapp/app/routes/magic.tsx

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import { authenticator } from "~/services/auth.server";
66
import { setLastAuthMethodHeader } from "~/services/lastAuthMethod.server";
77
import { getRedirectTo } from "~/services/redirectTo.server";
88
import { commitSession, getSession } from "~/services/sessionStorage.server";
9-
import { getReferralSource, clearReferralSourceCookie } from "~/services/referralSource.server";
10-
import { telemetry } from "~/services/telemetry.server";
9+
import { trackAndClearReferralSource } from "~/services/referralSource.server";
1110

1211
export async function loader({ request }: LoaderFunctionArgs) {
1312
const redirectTo = await getRedirectTo(request);
@@ -55,28 +54,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
5554
headers.append("Set-Cookie", await commitSession(session));
5655
headers.append("Set-Cookie", await setLastAuthMethodHeader("email"));
5756

58-
// Read referral source cookie and set in PostHog if present (only for new users), then clear it
59-
const referralSource = await getReferralSource(request);
60-
if (referralSource) {
61-
const user = await prisma.user.findUnique({
62-
where: { id: auth.userId },
63-
});
64-
if (user) {
65-
// Only set referralSource for new users (created within the last 30 seconds)
66-
const userAge = Date.now() - user.createdAt.getTime();
67-
const isNewUser = userAge < 30 * 1000; // 30 seconds
68-
69-
if (isNewUser) {
70-
telemetry.user.identify({
71-
user,
72-
isNewUser: true,
73-
referralSource,
74-
});
75-
}
76-
}
77-
// Clear the cookie after using it (regardless of whether we set it)
78-
headers.append("Set-Cookie", await clearReferralSourceCookie());
79-
}
57+
await trackAndClearReferralSource(request, auth.userId, headers);
8058

8159
return redirect(redirectTo ?? "/", { headers });
8260
}

0 commit comments

Comments
 (0)