encore-code-review

Par encoredev · skills

Examinez le code Encore.ts pour détecter les bonnes pratiques et les anti-patterns.

npx skills add https://github.com/encoredev/skills --skill encore-code-review

Examen du code Encore

Instructions

Lors de l'examen du code Encore.ts, vérifiez ces problèmes courants :

Problèmes critiques

1. Infrastructure à l'intérieur des fonctions

// WRONG: Infrastructure declared inside function
async function setup() {
  const db = new SQLDatabase("mydb", { migrations: "./migrations" });
  const topic = new Topic<Event>("events", { deliveryGuarantee: "at-least-once" });
}

// CORRECT: Package level declaration
const db = new SQLDatabase("mydb", { migrations: "./migrations" });
const topic = new Topic<Event>("events", { deliveryGuarantee: "at-least-once" });

2. Utiliser require() au lieu de import

// WRONG
const { api } = require("encore.dev/api");

// CORRECT
import { api } from "encore.dev/api";

3. Mauvais modèle d'importation de service

// WRONG: Direct import from another service
import { getUser } from "../user/api";

// CORRECT: Use ~encore/clients
import { user } from "~encore/clients";
const result = await user.getUser({ id });

4. Gestion des erreurs manquante

// WRONG: Returning null for not found
const user = await db.queryRow`SELECT * FROM users WHERE id = ${id}`;
if (!user) return null;

// CORRECT: Throw APIError
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. Risque d'injection SQL

// WRONG: String concatenation
await db.query(`SELECT * FROM users WHERE email = '${email}'`);

// CORRECT: Template literal with automatic escaping
await db.queryRow`SELECT * FROM users WHERE email = ${email}`;

Avertissements

6. Annotations de type manquantes

// WEAK: No explicit types
export const getUser = api(
  { method: "GET", path: "/users/:id", expose: true },
  async ({ id }) => {
    return await findUser(id);
  }
);

// BETTER: Explicit request/response types
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. Points d'accès internes exposés

// CHECK: Should this cron endpoint be exposed?
export const cleanupJob = api(
  { expose: true },  // Probably should be false
  async () => { /* ... */ }
);

8. Gestionnaires d'abonnement non idempotents

// RISKY: Not idempotent (pubsub has at-least-once delivery)
const _ = new Subscription(orderCreated, "process-order", {
  handler: async (event) => {
    await chargeCustomer(event.orderId);  // Could charge twice!
  },
});

// SAFER: Check before processing
const _ = new Subscription(orderCreated, "process-order", {
  handler: async (event) => {
    const order = await getOrder(event.orderId);
    if (order.status !== "pending") return;  // Already processed
    await chargeCustomer(event.orderId);
  },
});

9. Secrets appelés au niveau du module

// WRONG: Secret accessed at startup
const stripeKey = secret("StripeKey");
const client = new Stripe(stripeKey());  // Called during import

// CORRECT: Access inside functions
const stripeKey = secret("StripeKey");

async function charge() {
  const client = new Stripe(stripeKey());  // Called at runtime
}

Checklist d'examen

  • [ ] Toute l'infrastructure au niveau du package
  • [ ] Utilisation des imports ES6, pas de require()
  • [ ] Les appels entre services utilisent ~encore/clients
  • [ ] Gestion des erreurs appropriée avec APIError
  • [ ] Les requêtes SQL utilisent des template literals
  • [ ] Types de requête/réponse définis
  • [ ] Les points d'accès internes ont expose: false
  • [ ] Les gestionnaires d'abonnement sont idempotents
  • [ ] Les secrets sont accédés à l'intérieur des fonctions, pas lors de l'importation
  • [ ] Les migrations suivent la convention de nommage (001_name.up.sql)

Format de sortie

Lors de l'examen, signalez les problèmes comme suit :

[CRITICAL] [file:line] Description de l'issue
[WARNING] [file:line] Description de la préoccupation
[GOOD] Bonne pratique notable observée

Skills similaires