+
Skip to content
3 changes: 3 additions & 0 deletions apps/web/app/api/analytics/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const GET = withWorkspace(
analyticsPathParamsSchema.parse(params);

// for backwards compatibility (we used to support /analytics/[endpoint] as well)
// @ts-expect-error FIXME zod transform error
if (!oldType && oldEvent && VALID_ANALYTICS_ENDPOINTS.includes(oldEvent)) {
oldType = oldEvent;
oldEvent = undefined;
Expand All @@ -49,7 +50,9 @@ export const GET = withWorkspace(

let link: Link | null = null;

// @ts-expect-error FIXME
event = oldEvent || event;
// @ts-expect-error FIXME
groupBy = oldType || groupBy;

if (programId) {
Expand Down
1 change: 1 addition & 0 deletions apps/web/app/api/resend/webhook/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const POST = async (req: Request) => {
// Need to base64 decode the secret
const secretBytes = Buffer.from(secret.split("_")[1], "base64");
const signature = crypto
Comment on lines 20 to 22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden secret decoding; current split can throw.

secret.split("_")[1] can be undefined if the format changes, causing a 500. Validate before decoding.

-  // Need to base64 decode the secret
-  const secretBytes = Buffer.from(secret.split("_")[1], "base64");
+  // Need to base64 decode the secret (expecting "resend_<base64>")
+  const parts = secret.split("_");
+  if (parts.length < 2 || !parts[1]) {
+    return NextResponse.json({ message: "Invalid secret" }, { status: 400 });
+  }
+  const secretBytes = Buffer.from(parts[1], "base64");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Need to base64 decode the secret
const secretBytes = Buffer.from(secret.split("_")[1], "base64");
const signature = crypto
// Need to base64 decode the secret (expecting "resend_<base64>")
const parts = secret.split("_");
if (parts.length < 2 || !parts[1]) {
return NextResponse.json({ message: "Invalid secret" }, { status: 400 });
}
const secretBytes = Buffer.from(parts[1], "base64");
const signature = crypto
🤖 Prompt for AI Agents
In apps/web/app/api/resend/webhook/route.ts around lines 20 to 22, the code
directly uses secret.split("_")[1] which can be undefined and cause Buffer.from
to throw; validate the secret format before decoding by checking secret is a
string, contains an underscore, and that split yields a non-empty second
segment, and handle the invalid case gracefully (return a 400/unauthorized
response or log and abort) instead of letting it throw; then safely
base64-decode the validated segment (and wrap decoding in a try/catch to handle
malformed base64) and proceed to compute the signature.

// @ts-expect-error FIXME
.createHmac("sha256", secretBytes)
.update(signedContent)
.digest("base64");
Comment on lines +23 to 26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove ts-expect-error; use Node crypto explicitly and mark runtime.

TypeScript is likely resolving crypto to the Web Crypto Crypto type (no createHmac). Avoid the suppression by:

  • Importing from node:crypto with named APIs.
  • Declaring the route’s runtime as nodejs.
-import crypto from "crypto";
+import { createHmac, timingSafeEqual } from "node:crypto";

+export const runtime = "nodejs";
...
-  const signature = crypto
-  // @ts-expect-error FIXME
-    .createHmac("sha256", secretBytes)
+  const signature = createHmac("sha256", secretBytes)
     .update(signedContent)
     .digest("base64");

Also applies to: 2-2

🤖 Prompt for AI Agents
In apps/web/app/api/resend/webhook/route.ts around lines 23 to 26, remove the
"// @ts-expect-error FIXME" and stop relying on the ambient Web Crypto type;
instead import the Node API explicitly (e.g., import { createHmac } from
"node:crypto") and use that named function to compute the HMAC, and declare the
route runtime as Node.js by exporting the runtime constant (export const runtime
= "nodejs") at the top of the file so TypeScript resolves node:crypto correctly
at runtime.

Expand Down
1 change: 0 additions & 1 deletion apps/web/lib/analytics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ const partnerEventsSchema = eventsQuerySchema
interval: true,
start: true,
end: true,
groupBy: true,
page: true,
limit: true,
order: true,
Expand Down
5 changes: 2 additions & 3 deletions apps/web/lib/zod/schemas/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,11 @@ export const analyticsFilterTB = z
partnerId: true,
tenantId: true,
folderId: true,
sortBy: true,
}),
);

export const eventsFilterTB = analyticsFilterTB
.omit({ granularity: true, timezone: true, page: true, sortBy: true })
.omit({ granularity: true, timezone: true })
.and(
z.object({
offset: z.coerce.number().default(0),
Expand All @@ -336,7 +335,7 @@ const sortOrder = z
.describe("The sort order. The default is `desc`.");

export const eventsQuerySchema = analyticsQuerySchema
.omit({ groupBy: true, sortBy: true })
.omit({ groupBy: true })
.extend({
event: z
.enum(EVENT_TYPES)
Expand Down
1 change: 0 additions & 1 deletion apps/web/lib/zod/schemas/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,6 @@ export const bulkUpdateLinksBodySchema = z.object({
.default([]),
data: createLinkBodySchema
.omit({
id: true,
domain: true,
key: true,
externalId: true,
Expand Down
2 changes: 0 additions & 2 deletions apps/web/lib/zod/schemas/partner-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ export const PartnerProfileCustomerSchema = CustomerEnrichedSchema.pick({
});

export const partnerProfileAnalyticsQuerySchema = analyticsQuerySchema.omit({
workspaceId: true,
externalId: true,
tenantId: true,
programId: true,
Expand All @@ -111,7 +110,6 @@ export const partnerProfileAnalyticsQuerySchema = analyticsQuerySchema.omit({
});

export const partnerProfileEventsQuerySchema = eventsQuerySchema.omit({
workspaceId: true,
externalId: true,
tenantId: true,
programId: true,
Expand Down
1 change: 0 additions & 1 deletion apps/web/lib/zod/schemas/partners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,6 @@ export const createPartnerSchema = z.object({
publicStats: true,
tagId: true,
geo: true,
projectId: true,
programId: true,
partnerId: true,
webhookIds: true,
Expand Down
2 changes: 0 additions & 2 deletions apps/web/lib/zod/schemas/payouts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export const payoutsCountQuerySchema = payoutsQuerySchema
partnerId: true,
eligibility: true,
invoiceId: true,
excludeCurrentMonth: true,
})
.merge(
z.object({
Expand Down Expand Up @@ -79,7 +78,6 @@ export const PayoutResponseSchema = PayoutSchema.merge(

export const PartnerPayoutResponseSchema = PayoutResponseSchema.omit({
partner: true,
_count: true,
}).merge(
z.object({
program: ProgramSchema.pick({
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载