161 lines
6.5 KiB
Markdown
161 lines
6.5 KiB
Markdown
🤖 Codex Agent Guidelines for thirdweb-dev/js
|
||
|
||
Welcome, AI copilots! This guide captures the coding standards, architectural decisions, and workflow conventions that every automated agent (and human contributor!) must follow. Unless a rule explicitly targets a sub‑project, it applies repo‑wide.
|
||
|
||
⸻
|
||
|
||
1. GitHub Workflow & Etiquette
|
||
|
||
- Pull‑request titles must start with the affected workspace in brackets (e.g. [SDK], [Dashboard], [Portal], [Playground]).
|
||
- Begin the PR description with a one‑sentence summary, then add a checklist of changes and reference issues with Fixes #123.
|
||
- Keep commits small and topical – one logical change per commit.
|
||
- Branch names should follow area/brief-topic (e.g. sdk/fix-gas-estimate). Avoid personal names.
|
||
- Request at least one core maintainer review. Do not self‑merge unless you are the sole owner of that package.
|
||
- All CI checks (type‑check, Biome, tests) must pass before merging.
|
||
|
||
⸻
|
||
|
||
2. Formatting & Linting
|
||
|
||
- Biome governs formatting and linting; its rules live in biome.json.
|
||
- Run `pnpm fix` & `pnpm lint` before committing, make sure there are no linting errors.
|
||
- Avoid editor‑specific configs; rely on the shared settings.
|
||
- make sure everything builds after each file change by running `pnpm build`
|
||
|
||
⸻
|
||
|
||
3. TypeScript Style Guide
|
||
|
||
- Write idiomatic TypeScript: explicit function declarations and return types.
|
||
- Limit each file to one stateless, single‑responsibility function for clarity and testability.
|
||
- Re‑use shared types from @/types or local types.ts barrels.
|
||
- Prefer type aliases over interface except for nominal shapes.
|
||
- Avoid any and unknown unless unavoidable; narrow generics whenever possible.
|
||
- Choose composition over inheritance; leverage utility types (Partial, Pick, etc.).
|
||
|
||
⸻
|
||
|
||
4. Testing Strategy
|
||
|
||
- Co‑locate tests: foo.ts ↔ foo.test.ts.
|
||
- Use real function invocations with stub data; avoid brittle mocks.
|
||
- For network interactions, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce.
|
||
- Keep tests deterministic and side‑effect free; Vitest is pre‑configured.
|
||
- to run the tests: `cd packages thirdweb & pnpm test:dev <filename>`
|
||
|
||
⸻
|
||
|
||
5. packages/thirdweb
|
||
|
||
5.1 Public API Surface
|
||
|
||
- Export everything via the exports/ directory, grouped by feature.
|
||
- Every public symbol must have comprehensive TSDoc:
|
||
- Include at least one @example block that compiles.
|
||
- Tag with one custom annotation (@beta, @internal, @experimental, etc.).
|
||
- Comment only ambiguous logic; avoid restating TypeScript in prose.
|
||
|
||
5.2 Performance
|
||
|
||
- Lazy‑load heavy dependencies inside async paths to keep the initial bundle lean:
|
||
|
||
`const { jsPDF } = await import("jspdf");`
|
||
|
||
⸻
|
||
|
||
6. apps/dashboard & apps/playground
|
||
|
||
6.1 Core UI Toolkit
|
||
|
||
- Import primitives from @/components/ui/\_ (e.g. Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator).
|
||
- Use NavLink for internal navigation so active states are handled automatically.
|
||
- Group feature‑specific components under feature/components/\_ and expose a barrel index.ts when necessary.
|
||
|
||
6.2 Styling Conventions
|
||
|
||
- Tailwind CSS is the styling system – no inline styles or CSS modules.
|
||
- Merge class names with cn() from @/lib/utils to keep conditional logic readable.
|
||
- Stick to design tokens: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
|
||
- Expose a className prop on the root element of every component for overrides.
|
||
|
||
6.3 Component Patterns
|
||
|
||
- Server Components (run on the Node edge):
|
||
-- Read cookies/headers with next/headers.
|
||
-- Access server‑only environment variables or secrets.
|
||
-- Perform heavy data fetching that should not ship to the client.
|
||
-- Implement redirect logic with redirect() from next/navigation.
|
||
-- Start files with import "server-only"; to prevent client bundling.
|
||
- Client Components (run in the browser):
|
||
-- Begin files with 'use client'; before imports.
|
||
-- Handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks).
|
||
-- Access browser APIs (localStorage, window, IntersectionObserver, etc.).
|
||
-- Support fast transitions where data is prefetched on the client.
|
||
|
||
6.4 Data Fetching Guidelines
|
||
|
||
- Server Side
|
||
-- Always call getAuthToken() to retrieve the JWT from cookies.
|
||
-- Inject the token as an Authorization: Bearer header – never embed it in the URL.
|
||
-- Return typed results (Project[], User[], …) – avoid any.
|
||
- Client Side
|
||
-- Wrap calls in React Query (@tanstack/react-query).
|
||
-- Use descriptive, stable queryKeys for cache hits.
|
||
-- Configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s).
|
||
-- Keep tokens secret by calling internal API routes or server actions.
|
||
|
||
6.5 Analytics Event Reporting
|
||
|
||
- **When to create a new event**
|
||
-- Only add events that answer a clear product or business question.
|
||
-- Check `src/@/analytics/report.ts` first; avoid duplicates.
|
||
|
||
- **Naming conventions**
|
||
-- **Event name**: human-readable phrase in the form `<subject> <verb>` (e.g. "contract deployed").
|
||
-- **Reporting function**: `report<Subject><Verb>` (PascalCase).
|
||
-- All reporting helpers currently live in the shared `report.ts` file.
|
||
|
||
- **Boilerplate template**
|
||
-- Add a JSDoc header explaining **Why** the event exists and **Who** owns it (`@username`).
|
||
-- Accept a single typed `properties` object and forward it unchanged to `posthog.capture`.
|
||
-- Example:
|
||
|
||
```ts
|
||
/**
|
||
* ### Why do we need to report this event?
|
||
* - Tracks number of contracts deployed
|
||
*
|
||
* ### Who is responsible for this event?
|
||
* @jnsdls
|
||
*/
|
||
export function reportContractDeployed(properties: {
|
||
address: string;
|
||
chainId: number;
|
||
}) {
|
||
posthog.capture("contract deployed", properties);
|
||
}
|
||
```
|
||
|
||
- **Client-side only**: never import `posthog-js` in server components.
|
||
- **Housekeeping**: Inform **#eng-core-services** before renaming or removing an existing event.
|
||
|
||
⸻
|
||
|
||
7. Performance & Bundle Size
|
||
|
||
- Track bundle budgets via package.json#size-limit.
|
||
- Lazy‑import optional features; avoid top‑level side‑effects.
|
||
- De‑duplicate dependencies across packages through pnpm workspace hoisting.
|
||
|
||
⸻
|
||
|
||
8. Documentation & Developer Experience
|
||
|
||
- Each change in packages/\* should contain a changeset for the appropriate package, with the appropriate version bump
|
||
|
||
- patch for changes that don't impact the public API
|
||
- minor for any new/modified public API
|
||
|
||
- Surface breaking changes prominently in PR descriptions.
|
||
- For new UI components, add Storybook stories (\*.stories.tsx) alongside the code.
|