Skip to content

Deepen hook execution into a Hook Pipeline (architecture follow-up) #435

@borisno2

Description

@borisno2

Architecture-deepening candidate #2 (Worth exploring) from the improve-codebase-architecture review. Related to #434.

Problem

packages/core/src/hooks/index.ts exposes eight separate execute* functions — list + field variants of resolveInput, validate, beforeOperation, afterOperation. Each write call site in context/index.ts must invoke them in the correct order and thread resolvedData through by hand:

let resolvedData = await executeResolveInput(...)
resolvedData = await executeFieldResolveInputHooks(inputData, resolvedData, ...)
await executeValidate(... resolvedData ...)
await executeFieldValidateHooks(... resolvedData ...)

The "transform → validate" order and the data threading are knowledge held by the caller, not the module — orchestration leakage. Adding a phase touches every call site.

Deletion test → concentrates: replacing the loose functions with one pipeline object pulls the ordering/threading into one place; call sites shrink to "run, then check errors."

Proposed deepening

A HookPipeline with a small interface that owns the transform/validate span:

hookPipeline.run({ operation, inputData, item, listConfig, context })
  // → { resolvedData, validationErrors }

It runs, in order: list resolveInput → field resolveInput → list validate → field validate → built-in field rules. Call sites become const { resolvedData, validationErrors } = await hookPipeline.run(...).

Relationship to #434 (Write Pipeline)

These are complementary: the Write Pipeline (#434) calls the Hook Pipeline for the transform/validate span, then handles access, persistence, and after-hooks. This may be extracted as a sub-step of #434 or landed separately afterward — coordinate to avoid overlap. If #434 lands first and already isolates this span, downgrade/close this.

Acceptance criteria

  • A HookPipeline owns the transform+validate order; call sites no longer thread resolvedData or sequence hooks by hand.
  • Behaviour preserved: validation still throws ValidationError; hook arguments unchanged (Keystone-compliant).
  • Unit tests assert the order through the pipeline interface (spy hooks). Full packages/core suite stays green.
  • @opensaas/stack-core changeset (patch — internal refactor). Lint/format clean. No any/casts introduced.

Out of scope / notes

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions