Skip to content

API: createGuantr ​

The createGuantr function is the primary factory for creating Guantr instances. It is asynchronous and supports four overloads for maximum flexibility: you can initialize with options only, with a rule array, with a rule-defining callback, or with no arguments at all.

Importing ​

ts
import { createGuantr } from 'guantr';
import type { GuantrMeta, GuantrRule, GuantrOptions } from 'guantr';

Function Signatures ​

createGuantr is declared with four async overloads:

ts
// Overload 1 — Options only (no initial rules)
async function createGuantr<Meta>(options: GuantrOptions): Promise<Guantr<Meta>>;

// Overload 2 — Callback + optional options
async function createGuantr<Meta>(
  setRules: SetRulesCallback<Meta>,
  options?: GuantrOptions,
): Promise<Guantr<Meta>>;

// Overload 3 — Rule array + optional options
async function createGuantr<Meta>(
  setRules: GuantrRule<Meta>[],
  options?: GuantrOptions,
): Promise<Guantr<Meta>>;

// Overload 4 — No arguments (bare instance)
async function createGuantr<Meta>(): Promise<Guantr<Meta>>;

Overload dispatch logic ​

The first argument is inspected at runtime:

  • If it is an array (overload 3) or a function (overload 2), it is treated as the rules argument; the second argument (if provided) becomes options.
  • If it is an object (overload 1) or omitted (overload 4), it is treated as options.

When rules are provided, setRules() is called on the new instance immediately, meaning the instance is fully initialized before the returned promise resolves.

Generics ​

  • Meta: (Optional) A GuantrMeta<ResourceMap, Context> type object that provides strong typing for resources, actions, models, and context. When omitted, all resource keys and actions default to string, models default to Record<string, unknown>, and context defaults to Record<string, unknown>.

Parameters ​

options (GuantrOptions) ​

PropertyTypeDefaultDescription
contextContext | (() => Context | PromiseLike<Context>){}Evaluation context (static object) or a function that resolves it on each can/cannot check (once per batch for can.all/can.any etc.).
storageStorageInMemoryStorageCustom storage adapter implementing the Storage interface. Store rules in a database, Redis, or any backend of your choice.
maxRuleIterationsnumber1000Maximum number of rule evaluations per can/cannot check before the circuit breaker trips. Must be a positive integer; throws TypeError otherwise.

setRules (callback) ​

A SetRulesCallback<Meta> function receiving two helper functions:

ts
type SetRulesCallback<Meta> = (
  allow: (action: string, resource: string | [string, MatchConditionFn | Condition | null]) => void,
  deny: (action: string, resource: string | [string, MatchConditionFn | Condition | null]) => void,
) => void | Promise<void>;
  • allow(action, resource) — Registers an allow rule.
  • deny(action, resource) — Registers a deny rule.

The resource argument can be:

  • A string — an unconditional rule (no matchCondition).
  • A tuple [resourceKey, matchCondition] — a conditional rule. matchCondition can be a builder function (MatchConditionFn) that immediately produces a serialized Condition, a pre-built Condition object, or null (which is treated as unconditional).

Both allow and deny are synchronous — they build rule objects in memory. The callback itself may be async.

setRules (array) ​

An array of GuantrRule<Meta> objects:

ts
type GuantrRule<Meta> = {
  resource: string;
  action: string;
  matchCondition?: MatchConditionFn | Condition | null;
  effect: 'allow' | 'deny';
};

When a matchCondition is a function (MatchConditionFn), it is executed immediately during createGuantr and the resulting serialized Condition AST is stored in its place.

Returns ​

  • Promise<Guantr<Meta>> — A fully initialized Guantr instance. If rules were provided, they are already stored before the promise resolves.

Examples ​

Bare instance (no rules, no options) ​

ts
const guantr = await createGuantr();
// Set rules later
await guantr.setRules((allow, deny) => {
  allow('read', 'post');
});

With options only ​

ts
const guantr = await createGuantr<MyMeta>({
  storage: new MyCustomStorage(),
  context: async () => {
    const user = await getCurrentUser();
    return { userId: user?.id ?? null };
  },
  maxRuleIterations: 2000,
});

With rule array ​

ts
const guantr = await createGuantr<MyMeta>([
  { effect: 'allow', action: 'read', resource: 'post' },
  {
    effect: 'deny',
    action: 'read',
    resource: 'post',
    matchCondition: ({ eq, resource, literal }) => eq(resource('archived'), literal(true)),
  },
]);

With callback + options ​

ts
const guantr = await createGuantr<MyMeta>(
  async (allow, deny) => {
    allow('read', 'post');
    allow('edit', [
      'post',
      ({ eq, resource, context }) => eq(resource('ownerId'), context('userId')),
    ]);
    deny('delete', [
      'post',
      ({ eq, resource, literal }) => eq(resource('status'), literal('archived')),
    ]);
  },
  {
    storage: new MyCustomStorage(),
    context: async () => ({ userId: getCurrentUserId() }),
  },
);

With a pre-built Condition object ​

ts
import { createMatchConditionBuilder } from 'guantr';

const builder = createMatchConditionBuilder();
const archivedCondition = builder.eq(builder.resource('status'), builder.literal('archived'));

const guantr = await createGuantr([
  { effect: 'allow', action: 'read', resource: 'post' },
  {
    effect: 'deny',
    action: 'read',
    resource: 'post',
    matchCondition: archivedCondition, // pre-built, no function wrapper
  },
]);

Circuit breaker ​

When maxRuleIterations is exceeded during a can/cannot evaluation, the check throws a GuantrCircuitBreakerError instead of returning false. This prevents unbounded rule evaluation loops.

ts
const guantr = await createGuantr({ maxRuleIterations: 10 });
// If a check evaluates more than 10 rules, GuantrCircuitBreakerError is thrown.

See also ​