Skip to content
0

katanakit-js / DirectoryService

Class: DirectoryService ​

Defined in: src/core/services/directory.service.ts:211

User management over any storage, with the lockout guards built in.

Pure orchestration: every method either returns a DirectoryResult or hands the decision back to the repository. No exceptions for expected refusals — "you may not do that" is an answer, not a crash, and a caller should not have to distinguish the two in a catch.

Deliberately not here: deleting a provider account, revoking a live session, forcing a password change. Those belong to the identity provider and are the caller's to invoke — a directory row disappearing must not be the only thing that happened.

Example ​

ts
const directory = new DirectoryService({ repository });

const suspended = await directory.useSuspend(actor, 42, "left the company");
if (!suspended.ok && suspended.error.code === "last_owner") {
  // render the "promote someone else first" message
}

Constructors ​

Constructor ​

ts
new DirectoryService(__namedParameters): DirectoryService;

Defined in: src/core/services/directory.service.ts:214

Parameters ​

ParameterType
__namedParametersDirectoryServiceOptions

Returns ​

DirectoryService

Methods ​

useAddRole() ​

ts
useAddRole(
   actor, 
   id, 
   role
): Promise<DirectoryResult<{
  displayName?: string;
  email?: string;
  id: string | number;
  metadata?: Record<string, unknown>;
  principalSubject?: string;
  roles: string[];
  scope?: string;
  status: "pending" | "active" | "suspended" | "deactivated";
}>>;

Defined in: src/core/services/directory.service.ts:282

Grants a role. Refuses when the actor does not already hold it.

Parameters ​

ParameterType
actorDirectoryActor
idstring | number
rolestring

Returns ​

Promise<DirectoryResult<{ displayName?: string; email?: string; id: string | number; metadata?: Record<string, unknown>; principalSubject?: string; roles: string[]; scope?: string; status: "pending" | "active" | "suspended" | "deactivated"; }>>


useCreate() ​

ts
useCreate(actor, user): Promise<DirectoryResult<{
  displayName?: string;
  email?: string;
  id: string | number;
  metadata?: Record<string, unknown>;
  principalSubject?: string;
  roles: string[];
  scope?: string;
  status: "pending" | "active" | "suspended" | "deactivated";
}>>;

Defined in: src/core/services/directory.service.ts:239

Registers a person.

The actor is required even though creating is usually permissive: it is what lets a deployment decide later that creation is itself a capability, without changing this signature.

Parameters ​

ParameterType
actorDirectoryActor
userOmit<DirectoryUser, "id">

Returns ​

Promise<DirectoryResult<{ displayName?: string; email?: string; id: string | number; metadata?: Record<string, unknown>; principalSubject?: string; roles: string[]; scope?: string; status: "pending" | "active" | "suspended" | "deactivated"; }>>


useDelete() ​

ts
useDelete(actor, id): Promise<DirectoryResult<true>>;

Defined in: src/core/services/directory.service.ts:397

Removes the record permanently.

Separate from useSuspend on purpose — and it does not touch the provider account, so a caller who needs real revocation must do that too.

Parameters ​

ParameterType
actorDirectoryActor
idstring | number

Returns ​

Promise<DirectoryResult<true>>


useGet() ​

ts
useGet(id): Promise<DirectoryResult<{
  displayName?: string;
  email?: string;
  id: string | number;
  metadata?: Record<string, unknown>;
  principalSubject?: string;
  roles: string[];
  scope?: string;
  status: "pending" | "active" | "suspended" | "deactivated";
}>>;

Defined in: src/core/services/directory.service.ts:228

Fetches one user.

Parameters ​

ParameterType
idstring | number

Returns ​

Promise<DirectoryResult<{ displayName?: string; email?: string; id: string | number; metadata?: Record<string, unknown>; principalSubject?: string; roles: string[]; scope?: string; status: "pending" | "active" | "suspended" | "deactivated"; }>>


useList() ​

ts
useList(query?): Promise<DirectoryPageResult>;

Defined in: src/core/services/directory.service.ts:219

Lists users, filtered and paginated by the repository.

Parameters ​

ParameterType
queryPartial<DirectoryQuery>

Returns ​

Promise<DirectoryPageResult>


useReactivate() ​

ts
useReactivate(actor, id): Promise<DirectoryResult<{
  displayName?: string;
  email?: string;
  id: string | number;
  metadata?: Record<string, unknown>;
  principalSubject?: string;
  roles: string[];
  scope?: string;
  status: "pending" | "active" | "suspended" | "deactivated";
}>>;

Defined in: src/core/services/directory.service.ts:372

Returns a suspended account to service.

Parameters ​

ParameterType
actorDirectoryActor
idstring | number

Returns ​

Promise<DirectoryResult<{ displayName?: string; email?: string; id: string | number; metadata?: Record<string, unknown>; principalSubject?: string; roles: string[]; scope?: string; status: "pending" | "active" | "suspended" | "deactivated"; }>>


useRemoveRole() ​

ts
useRemoveRole(
   actor, 
   id, 
   role
): Promise<DirectoryResult<{
  displayName?: string;
  email?: string;
  id: string | number;
  metadata?: Record<string, unknown>;
  principalSubject?: string;
  roles: string[];
  scope?: string;
  status: "pending" | "active" | "suspended" | "deactivated";
}>>;

Defined in: src/core/services/directory.service.ts:312

Revokes a role, keeping the person active.

Parameters ​

ParameterType
actorDirectoryActor
idstring | number
rolestring

Returns ​

Promise<DirectoryResult<{ displayName?: string; email?: string; id: string | number; metadata?: Record<string, unknown>; principalSubject?: string; roles: string[]; scope?: string; status: "pending" | "active" | "suspended" | "deactivated"; }>>


useSuspend() ​

ts
useSuspend(
   actor, 
   id, 
   reason?
): Promise<DirectoryResult<{
  displayName?: string;
  email?: string;
  id: string | number;
  metadata?: Record<string, unknown>;
  principalSubject?: string;
  roles: string[];
  scope?: string;
  status: "pending" | "active" | "suspended" | "deactivated";
}>>;

Defined in: src/core/services/directory.service.ts:340

Suspends access while keeping the record and its audit trail.

This is the operation a real offboarding uses, and it is notuseDelete. Removing the row loses the evidence that the account existed; leaving the account merely "inactive" in a provider that has no such state means someone can still sign in. Suspension is the reversible, auditable middle ground, and useDelete is reserved for a genuine correction.

Parameters ​

ParameterType
actorDirectoryActor
idstring | number
reason?string

Returns ​

Promise<DirectoryResult<{ displayName?: string; email?: string; id: string | number; metadata?: Record<string, unknown>; principalSubject?: string; roles: string[]; scope?: string; status: "pending" | "active" | "suspended" | "deactivated"; }>>


useUpdate() ​

ts
useUpdate(
   actor, 
   id, 
   patch
): Promise<DirectoryResult<{
  displayName?: string;
  email?: string;
  id: string | number;
  metadata?: Record<string, unknown>;
  principalSubject?: string;
  roles: string[];
  scope?: string;
  status: "pending" | "active" | "suspended" | "deactivated";
}>>;

Defined in: src/core/services/directory.service.ts:258

Patches a user's fields.

Roles go through the demotion guards even here, because an update that silently accepts { roles: [] } is a way around useRemoveRole entirely.

Parameters ​

ParameterType
actorDirectoryActor
idstring | number
patchPartial<Omit<DirectoryUser, "id">>

Returns ​

Promise<DirectoryResult<{ displayName?: string; email?: string; id: string | number; metadata?: Record<string, unknown>; principalSubject?: string; roles: string[]; scope?: string; status: "pending" | "active" | "suspended" | "deactivated"; }>>

Released under the MIT License.