| name | encore-code-review |
| description | Review Encore.ts code for best practices and anti-patterns. |
Encore Code Review
Instructions
When reviewing Encore.ts code, check for these common issues:
Critical Issues
1. Infrastructure Inside Functions
async function setup() {
const db = new SQLDatabase("mydb", { migrations: "./migrations" });
const topic = new Topic<Event>("events", { deliveryGuarantee: "at-least-once" });
}
const db = new SQLDatabase("mydb", { migrations: "./migrations" });
const topic = new Topic<Event>("events", { deliveryGuarantee: "at-least-once" });
2. Using require() Instead of import
const { api } = require("encore.dev/api");
import { api } from "encore.dev/api";
3. Wrong Service Import Pattern
import { getUser } from "../user/api";
import { user } from "~encore/clients";
const result = await user.getUser({ id });
4. Missing Error Handling
const user = await db.queryRow`SELECT * FROM users WHERE id = ${id}`;
if (!user) return null;
import { APIError } from "encore.dev/api";
const user = await db.queryRow`SELECT * FROM users WHERE id = ${id}`;
if (!user) {
throw APIError.notFound("user not found");
}
5. SQL Injection Risk
await db.query(`SELECT * FROM users WHERE email = '${email}'`);
await db.queryRow`SELECT * FROM users WHERE email = ${email}`;
Warning Issues
6. Missing Type Annotations
export const getUser = api(
{ method: "GET", path: "/users/:id", expose: true },
async ({ id }) => {
return await findUser(id);
}
);
interface GetUserRequest { id: string; }
interface User { id: string; email: string; name: string; }
export const getUser = api(
{ method: "GET", path: "/users/:id", expose: true },
async ({ id }: GetUserRequest): Promise<User> => {
return await findUser(id);
}
);
7. Exposed Internal Endpoints
export const cleanupJob = api(
{ expose: true },
async () => { }
);
8. Non-Idempotent Subscription Handlers
const _ = new Subscription(orderCreated, "process-order", {
handler: async (event) => {
await chargeCustomer(event.orderId);
},
});
const _ = new Subscription(orderCreated, "process-order", {
handler: async (event) => {
const order = await getOrder(event.orderId);
if (order.status !== "pending") return;
await chargeCustomer(event.orderId);
},
});
9. Secrets Called at Module Level
const stripeKey = secret("StripeKey");
const client = new Stripe(stripeKey());
const stripeKey = secret("StripeKey");
async function charge() {
const client = new Stripe(stripeKey());
}
Review Checklist
Output Format
When reviewing, report issues as:
[CRITICAL] [file:line] Description of issue
[WARNING] [file:line] Description of concern
[GOOD] Notable good practice observed