Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Handler Options

The options object reference

The handler's first argument is an options object containing context, errors, and other utilities.

Options Structure

.handler((options, ...inputs) => {
  const { 
    context,  // Merged context object
    errors,   // Typed error helpers (if .errors() defined)
    env       // Validated environment variables (if .env() defined)
  } = options;
  
  // Your logic here
})

context

The merged context from .context() and .callable({ context }):

const proc = zagora()
  .context({ db: myDb })
  .input(z.string())
  .handler(({ context }, id) => {
    return context.db.find(id);
  })
  .callable({ context: { logger: console } });
 
// Handler receives: { db: myDb, logger: console }

errors

Typed error helper functions when .errors() is defined:

const proc = zagora()
  .errors({
    NOT_FOUND: z.object({ id: z.string() }),
    FORBIDDEN: z.object({ reason: z.string() })
  })
  .handler(({ errors }, id) => {
    throw errors.NOT_FOUND({ id });
    // or
    throw errors.FORBIDDEN({ reason: 'No access' });
  })
  .callable();

Each helper creates a throwable error that Zagora catches and returns as a typed result.

env

Validated environment variables when .env() is defined:

const proc = zagora()
  .env(z.object({
    API_KEY: z.string(),
    TIMEOUT: z.coerce.number().default(5000)
  }))
  .handler(({ env }) => {
    console.log(env.API_KEY);   // string
    console.log(env.TIMEOUT);   // number
  })
  .callable({ env: process.env });

Disabling Options

Use disableOptions: true to omit the options object entirely:

const add = zagora({ disableOptions: true })
  .input(z.tuple([z.number(), z.number()]))
  .handler((a, b) => a + b)  // No options object!
  .callable();

Options with Different Input Types

Object Input

.input(z.object({ name: z.string() }))
.handler((options, input) => {
  // input: { name: string }
})

Tuple Input (Spread)

.input(z.tuple([z.string(), z.number()]))
.handler((options, name, age) => {
  // name: string, age: number
})

Primitive Input

.input(z.string())
.handler((options, input) => {
  // input: string
})

Array Input

.input(z.array(z.number()))
.handler((options, numbers) => {
  // numbers: number[]
})

No Input

.handler((options) => {
  // No input arguments
})

Pattern: Destructuring

Common pattern for cleaner handlers:

.handler(({ context, errors, env }, input) => {
  const { db, logger } = context;
  
  logger.info('Processing:', input);
  const result = db.query(input);
  
  if (!result) {
    throw errors.NOT_FOUND({ id: input });
  }
  
  return result;
})

Next Steps