d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
72 lines
3.2 KiB
Plaintext
72 lines
3.2 KiB
Plaintext
---
|
|
description: Global coding standards that apply to all files
|
|
alwaysApply: true
|
|
---
|
|
# Global Standards
|
|
|
|
## Logging
|
|
Import `createLogger` from `@sim/logger`. Use `logger.info`, `logger.warn`, `logger.error` instead of `console.log`. Inside API routes wrapped with `withRouteHandler`, loggers automatically include the request ID.
|
|
|
|
## API Route Handlers
|
|
All API route handlers must be wrapped with `withRouteHandler` from `@/lib/core/utils/with-route-handler`. Never export a bare `async function GET/POST/...` — always use `export const METHOD = withRouteHandler(...)`.
|
|
|
|
## Comments
|
|
Use TSDoc for documentation. No `====` separators. No non-TSDoc comments.
|
|
|
|
## Styling
|
|
Never update global styles. Keep all styling local to components.
|
|
|
|
## ID Generation
|
|
Never use `crypto.randomUUID()`, `nanoid`, or the `uuid` package directly. Use the utilities from `@sim/utils/id`:
|
|
|
|
- `generateId()` — UUID v4, use by default
|
|
- `generateShortId(size?)` — short URL-safe ID (default 21 chars), for compact identifiers
|
|
|
|
Both use `crypto.getRandomValues()` under the hood and work in all contexts including non-secure (HTTP) browsers.
|
|
|
|
```typescript
|
|
// ✗ Bad
|
|
import { nanoid } from 'nanoid'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
const id = crypto.randomUUID()
|
|
|
|
// ✓ Good
|
|
import { generateId, generateShortId } from '@sim/utils/id'
|
|
const uuid = generateId()
|
|
const shortId = generateShortId()
|
|
const tiny = generateShortId(8)
|
|
```
|
|
|
|
## Common Utilities
|
|
Use shared helpers from `@sim/utils` instead of writing inline implementations:
|
|
|
|
- `sleep(ms)` from `@sim/utils/helpers` — async delay. Never write `new Promise(resolve => setTimeout(resolve, ms))`
|
|
- `toError(value)` from `@sim/utils/errors` — normalize unknown caught values to `Error`. Never write `e instanceof Error ? e : new Error(String(e))`
|
|
- `getErrorMessage(value, fallback?)` from `@sim/utils/errors` — extract error message string. Never write `e instanceof Error ? e.message : 'fallback'`
|
|
- `structuredClone(value)` — built-in deep clone, no import needed. Never write `JSON.parse(JSON.stringify(obj))`
|
|
- `omit(obj, keys)` from `@sim/utils/object` — remove keys from object
|
|
- `filterUndefined(obj)` from `@sim/utils/object` — strip undefined-valued keys. Never write `Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined))`
|
|
- `truncate(str, maxLength, suffix?)` from `@sim/utils/string` — safe string truncation with ellipsis
|
|
- `backoffWithJitter(attempt, retryAfterMs, options?)` from `@sim/utils/retry` — exponential backoff with jitter
|
|
- `parseRetryAfter(header)` from `@sim/utils/retry` — parse HTTP `Retry-After` header to milliseconds
|
|
|
|
```typescript
|
|
// ✗ Bad
|
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
const msg = error instanceof Error ? error.message : 'Unknown error'
|
|
const clone = JSON.parse(JSON.stringify(obj))
|
|
const filtered = Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined))
|
|
|
|
// ✓ Good
|
|
import { sleep } from '@sim/utils/helpers'
|
|
import { getErrorMessage, toError } from '@sim/utils/errors'
|
|
import { filterUndefined } from '@sim/utils/object'
|
|
await sleep(1000)
|
|
const msg = getErrorMessage(error, 'Unknown error')
|
|
const clone = structuredClone(obj)
|
|
const filtered = filterUndefined(obj)
|
|
```
|
|
|
|
## Package Manager
|
|
Use `bun` and `bunx`, not `npm` and `npx`.
|