- name
- kickjs-deny-list
- description
- Patterns to refuse outright when the user asks for them — they break v4 invariants.
<!-- Generated by `kick g agents` for kick-fullstack-server. Edits are overwritten on the next refresh; keep customisation in a SKILL.local.md alongside. -->
**Module / adapter / plugin shape**:
- `class implements AppAdapter` → use `defineAdapter()`.
- `class implements KickPlugin` / function returning `KickPlugin` → use `definePlugin()`.
- `class implements AppModule` for new code → use `defineModule()`.
- `bootstrap({ adapters: [MyAdapter] })` (factory) → `MyAdapter()` (instance, with parens).
- `@Controller('/path')` with a path argument → drop the path; set the mount via `routes().path`. The decorator path is OpenAPI metadata only.
- Module file named `<name>.ts` (no `.module` suffix) → rename to `<name>.module.ts`. Vite HMR's glob doesn't pick up the unsuffixed form.
**DI**:
- `new Container()` or `Container.getInstance().reset()` in tests → use `Container.reset()` in `beforeEach` (or `Container.create()` for fully isolated graphs).
- DI tokens with `:` separator (`'app:db:url'`) or in PascalCase → use slash-delimited lower-case (`'app/db/url'`). First-party uses reserved `'kick/'` prefix.
- `Symbol.for(...)` for DI tokens — globally interned, **collides across files**. Use `createToken<T>('name')`.
- Raw string tokens (`@Inject('config')`) — silent collisions; widens to `unknown`. Use `createToken<T>`.
- Injecting a `Scope.REQUEST` service into a `SINGLETON` — container throws at resolve time.
**Bootstrap / entry file**:
- `bootstrap({ ... })` without `export const app = ...` → always export. HMR degrades to full restart and `createTestApp` loses the handle.
- `bootstrap({ register: ... })` — that option doesn't exist. Use an inline plugin in `plugins`.
**Middleware**:
- Using `(ctx, next)` for global middleware in `bootstrap({ middlewares })` — global middleware uses raw Express `(req, res, next)`. Wrong signature throws "Cannot read properties of undefined".
- Using `(req, res, next)` for an `@Middleware()` decorator — those use `(ctx, next)`.
- `@Middleware()` whose only output is `ctx.set('x', v)` — should be a context decorator (typed, ordered, testable).
**Context contributors**:
- `ctx.tenant = x` from a contributor — only sticks to one `RequestContext` instance. **Return the value** so the runner writes it via `ctx.set(key, value)`.
- Omitting the `declare module '@forinda/kickjs'` block — without it `ctx.get('tenant')` is `unknown`. (`defineAugmentation` is deprecated and was never a substitute for it.)
- `getRequestValue<string>('traceId')` — generic is the **key** type, not value type.
**Env / config**:
- `@Value('NEW_KEY')` without the key in the Zod schema — silent fallback to raw `process.env`, no coercion.
- `resetEnvCache()` outside tests — drops the registered schema.
**List endpoints**:
- Reading `req.query.status` directly — bypasses the allow-list. Use `ctx.qs({ filterable })`.
- Returning a bare array from a list endpoint — breaks the `PaginatedResponse<T>` contract. Use `ctx.paginate()`.
**Assets**:
- Hand-rolled `__dirname` arithmetic for template paths — use `assets.<ns>.<key>()` and add the namespace to `kick.config.ts assetMap`.
View on GitHub