Контекст hook и wiring
EntityHookContext
typescript
interface EntityHookContext<TInput = unknown, TItem = unknown> {
entity: EntityHookEntity;
phase: EntityHookPhase;
keystoneContext: KeystoneContext;
session?: Session;
spaceId?: string;
input?: TInput;
item?: TItem;
ability?: SpaceAbilityChecker; // если userId + spaceId
fields: Record<string, string>; // EAV для entity
extensionId: string; // handler owner
services: ExtensionBackendHostApis;
}ability
Строится в runner при наличии userId и spaceId:
ts
hookCtx.ability?.assert('artifact.create');
hookCtx.ability?.can('my-ext.approve');fields
Автоматически getEntityFieldValues для entity + id из input или item.
Wiring points (host)
| Entry | Hooks |
|---|---|
artifact-mutation.service.ts | create, move, tags, star |
artifact-versioning.service.ts | saveVersion |
working-copy.service.ts | commit → afterSaveVersion |
| Keystone Space, Artifact, SpaceMember, Template | thin adapter → runner |
Полный список смотрите в entity-hooks/ и call sites runEntityHooks.
Регистрация
ts
import { defineExtension } from '@artiroute/extension-sdk/extension';
export default defineExtension((ctx) => {
ctx.registerEntityHook(
'artifact',
'beforeCreate',
async (hookCtx) => {
// ...
},
100, // order: меньше = раньше
);
});Manifest:
js
{ registryId: 'backend.entityHooks', keys: ['artifact:beforeCreate'] }Keys в manifest — документация surface; фактическая привязка по entity+phase в коде.
Ошибки
abort → EntityHookAbortError → GraphQL error с code / message.
Тестирование
pnpm build:extensions && pnpm install:extensions- Создать artifact с именем
__registry_test_abort__в space с registry-test — ожидается abort - Unit tests:
apps/backend/src/modules/entity-hooks/(если есть)