Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/24289-hook-ctx-title-doors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@objectstack/skills': patch
---

docs(skills): `objectstack-data` says which hook doors provide `ctx.title` — a `body` has it, a deprecated `handler` gets it at runtime without `HookContext` declaring it, and `ql.registerHook` and a bare `ObjectQL` `bindHooks` do not provide it (#24289)

Clause-②: no

`skills/objectstack-data/references/data-hooks.md` listed `ctx.title(field?)` in the sandbox `ctx` table with no qualifier, so it read as a member of every hook context. It is not: a sandboxed `body` has it (the recommended form); an inline or named `handler`, which is deprecated, is handed it at runtime when the runtime binds the stack's hooks, but `HookContext` does not declare it, so a handler annotated with that type fails to compile; a hook registered with `ql.registerHook(...)`, or bound through `ObjectQL.bindHooks` with no runtime, gets no `ctx.title` at all. The row now says so. Text only; nothing an author writes changes, and no hook context changes.
2 changes: 1 addition & 1 deletion skills/objectstack-data/references/data-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ The sandbox is handed a **JSON snapshot** of these (built by
| `ctx.api` | object | Cross-object CRUD. Gated by `api.read` / `api.write` — see below. |
| `ctx.log` | `{ debug, info, warn, error }` | Gated by `log`. Call **`ctx.log.info(msg, data?)`** — `ctx.log` is an **object, not** callable as `ctx.log(msg)`. Emission is **best-effort** (see Troubleshooting). |
| `ctx.crypto` | `{ randomUUID }` | Gated by `crypto.uuid`. |
| `ctx.title` | `(field?) => Promise<string \| null>` | **Name the record instead of printing its id.** `await ctx.title()` resolves this object's `nameField` — including when it is a **formula**, evaluated server-side, with no extra read. `await ctx.title('account_id')` resolves the related record's title through a lookup column (one `findOne`, gated by `api.read`; the no-argument form needs no capability). `null` when there is no title — it never falls back to the id. |
| `ctx.title` | `(field?) => Promise<string \| null>` | **Name the record, not its id.** `ctx.title()` resolves this object's `nameField`, a **formula** included (no extra read); `ctx.title('account_id')` resolves a lookup's title (needs `api.read`). `null` when there is no title, never the id. **Per door:** `body` has it; a deprecated `handler` gets it at runtime, undeclared on `HookContext` (TS2339 when annotated) — use `body`; `ql.registerHook` and a bare `ObjectQL` `bindHooks` lack it. |

(Action bodies additionally receive `ctx.recordId` and `ctx.record`, and their
wrap is `(async (input, ctx) => { … })(input, ctx)` — the action params arrive as
Expand Down
Loading