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
import { createGuantr } from 'guantr';
import type { GuantrMeta, GuantrRule, GuantrOptions } from 'guantr';Function Signatures
createGuantr is declared with four async overloads:
// 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) AGuantrMeta<ResourceMap, Context>type object that provides strong typing for resources, actions, models, and context. When omitted, all resource keys and actions default tostring, models default toRecord<string, unknown>, and context defaults toRecord<string, unknown>.
Parameters
options (GuantrOptions)
| Property | Type | Default | Description |
|---|---|---|---|
context | Context | (() => 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.). |
storage | Storage | InMemoryStorage | Custom storage adapter implementing the Storage interface. Store rules in a database, Redis, or any backend of your choice. |
maxRuleIterations | number | 1000 | Maximum 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:
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 anallowrule.deny(action, resource)— Registers adenyrule.
The resource argument can be:
- A string — an unconditional rule (no
matchCondition). - A tuple
[resourceKey, matchCondition]— a conditional rule.matchConditioncan be a builder function (MatchConditionFn) that immediately produces a serializedCondition, a pre-builtConditionobject, ornull(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:
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 initializedGuantrinstance. If rules were provided, they are already stored before the promise resolves.
Examples
Bare instance (no rules, no options)
const guantr = await createGuantr();
// Set rules later
await guantr.setRules((allow, deny) => {
allow('read', 'post');
});With options only
const guantr = await createGuantr<MyMeta>({
storage: new MyCustomStorage(),
context: async () => {
const user = await getCurrentUser();
return { userId: user?.id ?? null };
},
maxRuleIterations: 2000,
});With rule array
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
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
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.
const guantr = await createGuantr({ maxRuleIterations: 10 });
// If a check evaluates more than 10 rules, GuantrCircuitBreakerError is thrown.See also
new Guantr()— Alternative direct construction.setRules()— Update rules after creation.- Error Classes —
GuantrCircuitBreakerErrorandGuantrInvalidConditionKeyError.