Skip to content

Hooks & pipelines

Server-side collection behavior lives in TypeScript beside each collection module. Hooks and pipelines are declared on defineCollection() in collections/<name>/<name>.collection.ts — they compile into the build output and run inside the runtime with full policy evaluation.

Hooks

Hooks react to collection lifecycle events: validation, side effects, and computed fields on create, update, and delete. Add hooks.before / hooks.after under create, update, or delete on the collection definition.

import { defineCollection, text } from '@norbital-ai/pod/authoring';

export const payroll_runs = defineCollection('payroll_runs', {
  table: { /* … */ },
  create: {
    input: { columns: { /* … */ } },
    hooks: {
      before: async ({ input, api }) => { /* validate */ return input; },
      after: async ({ input, api }) => { /* side effects */ }
    }
  },
  update: {
    input: { columns: { /* … */ } },
    hooks: {
      before: async ({ input, existing, api }) => input
    }
  }
});

Register collections in collections/index.ts and include them in defineWorkspaceRegistry({ collections }) in workspace.ts.

Use hooks for business rules that must run on every mutation — generating related records, recalculating totals, enforcing invariants, or calling external systems through facility bindings. Reads inside hooks use api.<collection>.findMany({ where, with }) only; writes belong in automation/.

Pipelines

Pipelines handle bulk export and import flows for a collection. Add top-level export and import handlers on the same defineCollection() definition.

import { defineCollection } from '@norbital-ai/pod/authoring';

export const payroll_runs = defineCollection('payroll_runs', {
  table: { /* … */ },
  export: async (ctx, api) => {
    const rows = await api.payroll_runs.findMany({ where: ctx.scope.where });
    return [{ label: 'Export', attachments: [/* … */], delivery: { method: 'download' } }];
  },
  import: async (ctx, api) => {
    /* parse ctx.scope.import_data → rows for upsert */
    return parsedRows;
  }
});

When to use which

  • Hooks — per-record mutations, validation, side effects on standard routes
  • Pipelines — structured export/import that reads many records and returns tabular output
  • Automations — scheduled or manual background jobs not tied to a single mutation
  • Remote functions — arbitrary server endpoints callable from apps or external clients