--- name: tibi-hook-authoring description: Write and debug server-side hooks for tibi-server (goja Go JS runtime). Covers IIFE structure, HookResponse/HookException types, context.filter Go-object quirk, single-item vs list retrieval, and MongoDB filter patterns. Use when creating or modifying files in api/hooks/. --- # tibi-hook-authoring ## Hook file structure Wrap every hook in an IIFE: ```js ;(function () { /** @type {HookResponse} */ const response = { status: 200 } // ... hook logic ... return response })() ``` Always return a `HookResponse` or throw a `HookException`. ## Type safety - Use inline JSDoc type casting: `/** @type {TypeName} */ (value)`. - Reference typed collection entries from `types/global.d.ts`. - Avoid `@ts-ignore`; use proper casting instead. - Use `const` and `let` instead of `var` — the goja runtime supports them. ## context.filter — Go object quirk `context.filter` is a Go object, not a regular JS object. Even when empty, it is **truthy**. Always check with `Object.keys()`: ```js const requestedFilter = context.filter && typeof context.filter === "object" && !Array.isArray(context.filter) && Object.keys(context.filter).length > 0 ? context.filter : null ``` **Never** use `context.filter || null` — it is always truthy and produces an empty filter inside `$and`, which crashes the Go server. ## Single-item vs. list retrieval For `GET /:collection/:id`, the Go server sets `_id` automatically from the URL parameter. GET read hooks should **not** set their own `_id` filter for `req.param("id")`. Only add authorization filters (e.g. `{ userId: userId }`). ## HookResponse fields (GET hooks) | Field | Purpose | | ------------- | ------------------------------------------------------------------- | | `filter` | MongoDB filter (list retrieval, or restrict single-item) | | `selector` | MongoDB projection (`{ field: 0 }` exclude, `{ field: 1 }` include) | | `offset` | Pagination offset | | `limit` | Pagination limit | | `sort` | Sort specification | | `pipelineMod` | Function to manipulate the aggregation pipeline | ## context.data for write hooks - `context.data` can be an array for bulk operations — always guard with `!Array.isArray(context.data)`. - For POST hooks, `context.data.id` may contain the new entry ID. - For PUT/PATCH, `req.param("id")` gives the entry ID.