Skip to main content

@idpass/data-collect-core / EntityDataManager

Class: EntityDataManager

Defined in: components/EntityDataManager.ts:141

Primary API interface for the ID PASS DataCollect library.

The EntityDataManager orchestrates all data operations including:

  • Form submission and event processing
  • Entity creation, modification, and querying
  • Data synchronization with remote servers and external systems
  • Audit trail management and duplicate detection

This class implements the Command Query Responsibility Segregation (CQRS) pattern, where all changes go through events (FormSubmissions) and queries access the current state through the EntityStore.

Examples

Basic usage:

import { EntityDataManager, EntityType, SyncLevel } from '@idpass/data-collect-core';

// Initialize the manager (typically done once)
const manager = new EntityDataManager(
eventStore,
entityStore,
eventApplierService,
externalSyncManager,
internalSyncManager
);

// Create a new individual
const individual = await manager.submitForm({
guid: uuidv4(),
entityGuid: uuidv4(),
type: 'create-individual',
data: { name: 'John Doe', age: 30 },
timestamp: new Date().toISOString(),
userId: 'user-123',
syncLevel: SyncLevel.LOCAL
});

// Create a household group
const group = await manager.submitForm({
guid: uuidv4(),
entityGuid: uuidv4(),
type: 'create-group',
data: { name: 'Smith Family' },
timestamp: new Date().toISOString(),
userId: 'user-123',
syncLevel: SyncLevel.LOCAL
});

// Add individual to group
await manager.submitForm({
guid: uuidv4(),
entityGuid: group.guid,
type: 'add-member',
data: { members: [{ guid: individual.guid, name: individual.data.name }] },
timestamp: new Date().toISOString(),
userId: 'user-123',
syncLevel: SyncLevel.LOCAL
});

Offline-first usage:

// Works completely offline
const offlineManager = new EntityDataManager(
eventStore,
entityStore,
eventApplierService
// No sync managers - offline only
);

// All operations work locally
const entity = await offlineManager.submitForm(formData);
const allEntities = await offlineManager.getAllEntities();

With synchronization:

// Sync with remote server
if (manager.hasInternalSyncManager()) {
await manager.sync();
}

// Check sync status
if (manager.isSyncing()) {
console.log('Sync in progress...');
}

Constructors

Constructor

new EntityDataManager(eventStore, entityStore, eventApplierService, externalSyncManager?, internalSyncManager?, authManager?): EntityDataManager

Defined in: components/EntityDataManager.ts:154

Creates a new EntityDataManager instance.

Parameters

eventStore

EventStore

Store for managing events/form submissions.

entityStore

EntityStore

Store for managing current entity state.

eventApplierService

EventApplierService

Service for applying events to entities.

externalSyncManager?

ExternalSyncManager

Optional manager for external system sync.

internalSyncManager?

InternalSyncManager

Optional manager for server sync.

authManager?

AuthManager

Optional manager for authentication.

Returns

EntityDataManager

Accessors

lastRefreshToken

Get Signature

get lastRefreshToken(): string | null

Defined in: components/EntityDataManager.ts:167

Returns the last refresh token received from the sync server after login. Used by mobile clients to store the token for offline silent re-authentication.

Returns

string | null

Methods

isSyncing()

isSyncing(): boolean

Defined in: components/EntityDataManager.ts:176

Checks if a synchronization operation is currently in progress.

Returns

boolean

True if sync is active, false otherwise.


isExternalSyncing()

isExternalSyncing(): boolean

Defined in: components/EntityDataManager.ts:188

Checks if an external synchronization operation is currently in progress.

Returns

boolean

True if external sync is active, false otherwise.


submitForm()

submitForm(formData): Promise<EntityDoc | null>

Defined in: components/EntityDataManager.ts:228

Submits a form to create or modify entities through the event sourcing system.

All modifications go through events (FormSubmissions) which are applied to create the new state.

Parameters

formData

FormSubmission

The form submission containing the event data.

Returns

Promise<EntityDoc | null>

The resulting entity after applying the event, or null if creation failed.

Example

// Create a new individual
const individual = await manager.submitForm({
guid: uuidv4(),
entityGuid: uuidv4(),
type: 'create-individual',
data: { name: 'John Doe', age: 30, email: 'john@example.com' },
timestamp: new Date().toISOString(),
userId: 'user-123',
syncLevel: SyncLevel.LOCAL
});

// Update an existing individual
const updated = await manager.submitForm({
guid: uuidv4(),
entityGuid: individual.guid,
type: 'update-individual',
data: { age: 31 }, // Only changed fields
timestamp: new Date().toISOString(),
userId: 'user-123',
syncLevel: SyncLevel.LOCAL
});

submitFormBatch()

submitFormBatch(events): Promise<{ success: boolean; applied: number; failed: FormSubmission[]; errors: string[]; }>

Defined in: components/EntityDataManager.ts:256

Submits a batch of form submissions atomically.

All events in the batch are processed in sequence. If any event fails, the error is thrown immediately and the caller is responsible for handling the partial state. The response includes the count of successfully applied events and details about the failing event.

This method is intended for server-side sync push handlers where it is critical that the client receives an accurate success or failure signal. On failure the client should NOT advance its sync cursor so that the failed events can be retried on the next push.

Parameters

events

FormSubmission[]

The ordered list of form submissions to process.

Returns

Promise<{ success: boolean; applied: number; failed: FormSubmission[]; errors: string[]; }>

An object describing the outcome: applied count and any error details.

Example

const result = await manager.submitFormBatch(events);
if (!result.success) {
console.error(`Batch failed after ${result.applied} events: ${result.errors}`);
}

getAllEvents()

getAllEvents(options?): Promise<FormSubmission[]>

Defined in: components/EntityDataManager.ts:297

Retrieves all events (form submissions) from the event store.

Provides access to the complete audit trail of all changes made to entities. Events are returned in chronological order.

Parameters

options?

ReadAuditOptions = {}

Returns

Promise<FormSubmission[]>

Array of all form submissions/events.

Example

const events = await manager.getAllEvents();

// Filter events by type
const createEvents = events.filter(e => e.type.startsWith('create-'));

// Filter events by user
const userEvents = events.filter(e => e.userId === 'user-123');

// Filter events by entity
const entityEvents = events.filter(e => e.entityGuid === 'entity-456');

getAllEntities()

getAllEntities(options?): Promise<EntityPair[]>

Defined in: components/EntityDataManager.ts:331

Retrieves all entities from the entity store.

Returns EntityPairs containing both the initial state (when first loaded/synced) and the current modified state. This enables change tracking and conflict resolution.

Parameters

options?

ReadAuditOptions = {}

Returns

Promise<EntityPair[]>

Array of entity pairs with initial and current state.

Example

const entities = await manager.getAllEntities();

// Find entities that have been modified locally
const modifiedEntities = entities.filter(pair =>
pair.initial.version !== pair.modified.version
);

// Get only individuals
const individuals = entities.filter(pair =>
pair.modified.type === EntityType.Individual
);

// Get only groups
const groups = entities.filter(pair =>
pair.modified.type === EntityType.Group
);

getEntity()

getEntity(id, options?): Promise<EntityPair>

Defined in: components/EntityDataManager.ts:368

Retrieves a specific entity by its internal database ID.

Parameters

id

string

Internal database ID of the entity.

options?

ReadAuditOptions = {}

Returns

Promise<EntityPair>

Entity pair with initial and current state.

Throws

When entity is not found.

Example

try {
const entityPair = await manager.getEntity('entity-123');

console.log('Original state:', entityPair.initial);
console.log('Current state:', entityPair.modified);

// Check if entity has been modified
const hasChanges = entityPair.initial.version !== entityPair.modified.version;

if (entityPair.modified.type === EntityType.Group) {
const group = entityPair.modified as GroupDoc;
console.log('Group members:', group.memberIds);
}
} catch (error) {
if (error instanceof AppError && error.code === 'ENTITY_NOT_FOUND') {
console.log('Entity does not exist');
}
}

getMembers()

getMembers(groupId): Promise<EntityPair[]>

Defined in: components/EntityDataManager.ts:488

Retrieves all members of a specific group.

Parameters

groupId

string

Internal database ID of the group.

Returns

Promise<EntityPair[]>

Array of entity pairs for all group members.

Throws

When group is not found or entity is not a group.

Example

try {
const members = await manager.getMembers('group-123');
console.log(`Group has ${members.length} members`);

members.forEach(member => {
console.log(`Member: ${member.modified.data.name}`);
});
} catch (error) {
if (error instanceof AppError && error.code === 'INVALID_GROUP') {
console.log('Group not found or invalid');
}
}

hasUnsyncedEvents()

hasUnsyncedEvents(): Promise<boolean>

Defined in: components/EntityDataManager.ts:513

Checks if there are any unsynced events waiting to be synchronized.

Only available when an InternalSyncManager is configured.

Returns

Promise<boolean>

True if there are unsynced events, false otherwise.

Example

if (await manager.hasUnsyncedEvents()) {
console.log('There are changes waiting to sync');
await manager.syncWithSyncServer();
}

getUnsyncedEventsCount()

getUnsyncedEventsCount(): Promise<number>

Defined in: components/EntityDataManager.ts:537

Gets the count of unsynced events waiting to be synchronized.

Only available when an InternalSyncManager is configured.

Returns

Promise<number>

Number of unsynced events.

Example

const count = await manager.getUnsyncedEventsCount();
console.log(`${count} events waiting to sync`);

if (count > 100) {
console.log('Large number of changes - consider syncing soon');
}

syncWithSyncServer()

syncWithSyncServer(): Promise<void>

Defined in: components/EntityDataManager.ts:565

Synchronizes local data with the remote sync server.

Performs a full bidirectional sync: pushes local changes to server and pulls remote changes to local storage.

Only available when an InternalSyncManager is configured.

Returns

Promise<void>

Throws

When sync fails or authentication is required.

Example

try {
console.log('Starting sync...');
await manager.syncWithSyncServer();
console.log('Sync completed successfully');
} catch (error) {
console.error('Sync failed:', error.message);
}

searchEntities()

searchEntities(criteria, options?): Promise<EntityPair[]>

Defined in: components/EntityDataManager.ts:594

Searches entities using specified criteria.

Parameters

criteria

SearchCriteria

Search criteria array with query conditions.

options?

ReadAuditOptions = {}

Returns

Promise<EntityPair[]>

Array of entity pairs matching the criteria.

Example

// Search for adults
const adults = await manager.searchEntities([
{ "data.age": { $gte: 18 } },
{ "type": "individual" }
]);

// Search for groups with specific name
const smithFamilies = await manager.searchEntities([
{ "data.name": { $regex: /smith/i } },
{ "type": "group" }
]);

// TODO: Document the exact query syntax supported

getAuditTrailByEntityGuid()

getAuditTrailByEntityGuid(entityGuid, options?): Promise<AuditLogEntry[]>

Defined in: components/EntityDataManager.ts:626

Retrieves the complete audit trail for a specific entity.

Parameters

entityGuid

string

Global unique identifier of the entity.

options?

ReadAuditOptions = {}

Returns

Promise<AuditLogEntry[]>

Array of audit log entries in chronological order.

Throws

When audit trail retrieval fails.

Example

try {
const auditTrail = await manager.getAuditTrailByEntityGuid('entity-123');

console.log(`Found ${auditTrail.length} audit entries`);
auditTrail.forEach(entry => {
console.log(`${entry.timestamp}: ${entry.action} by ${entry.userId}`);
});
} catch (error) {
if (error instanceof AppError && error.code === 'AUDIT_TRAIL_ERROR') {
console.error('Failed to retrieve audit trail');
}
}

getEventsSince()

getEventsSince(timestamp): Promise<FormSubmission[]>

Defined in: components/EntityDataManager.ts:683

Retrieves events created since a specific timestamp.

Useful for incremental sync operations and change tracking.

Parameters

timestamp

string

ISO timestamp to filter events from.

Returns

Promise<FormSubmission[]>

Array of events created after the specified timestamp.

Example

const lastSync = '2024-01-01T00:00:00Z';
const recentEvents = await manager.getEventsSince(lastSync);

console.log(`${recentEvents.length} events since last sync`);
recentEvents.forEach(event => {
console.log(`${event.timestamp}: ${event.type} on ${event.entityGuid}`);
});

getEventsSincePagination()

getEventsSincePagination(timestamp, limit): Promise<{ events: FormSubmission[]; nextCursor: string | Date | null; }>

Defined in: components/EntityDataManager.ts:708

Retrieves events since a timestamp with pagination support.

Parameters

timestamp

string

ISO timestamp to filter events from.

limit

number

Maximum number of events to return (default: 10).

Returns

Promise<{ events: FormSubmission[]; nextCursor: string | Date | null; }>

Object with events array and cursor for next page.

Example

let cursor = '2024-01-01T00:00:00Z';
let allEvents: FormSubmission[] = [];

do {
const result = await manager.getEventsSincePagination(cursor, 50);
allEvents.push(...result.events);
cursor = result.nextCursor;
} while (cursor);

console.log(`Retrieved ${allEvents.length} events total`);

closeConnection()

closeConnection(): Promise<void>

Defined in: components/EntityDataManager.ts:728

Closes all database connections and cleans up resources.

Should be called when the EntityDataManager is no longer needed to properly release database connections and prevent memory leaks.

Returns

Promise<void>

Example

// At application shutdown
await manager.closeConnection();
console.log('Database connections closed');

clearStore()

clearStore(): Promise<void>

Defined in: components/EntityDataManager.ts:748

Clears all data from both entity and event stores.

⚠️ WARNING: This permanently deletes all data! Only use for testing or when intentionally resetting the system.

Returns

Promise<void>

Example

// For testing only
if (process.env.NODE_ENV === 'test') {
await manager.clearStore();
console.log('Test data cleared');
}

saveAuditLogs()

saveAuditLogs(auditLogs): Promise<void>

Defined in: components/EntityDataManager.ts:776

Saves multiple audit log entries to the event store.

Parameters

auditLogs

AuditLogEntry[]

Array of audit log entries to save.

Returns

Promise<void>

Example

const auditLogs: AuditLogEntry[] = [
{
guid: 'audit-1',
timestamp: '2024-01-01T12:00:00Z',
userId: 'user-123',
action: 'create-individual',
eventGuid: 'event-456',
entityGuid: 'person-789',
changes: { name: 'John Doe' },
signature: 'sha256:abc123'
}
];

await manager.saveAuditLogs(auditLogs);

getAuditLogsSince()

getAuditLogsSince(since): Promise<AuditLogEntry[]>

Defined in: components/EntityDataManager.ts:794

Retrieves audit logs created since a specific timestamp.

Parameters

since

string

ISO timestamp to filter audit logs from.

Returns

Promise<AuditLogEntry[]>

Array of audit log entries created after the specified timestamp.

Example

const lastAuditSync = '2024-01-01T00:00:00Z';
const recentAudits = await manager.getAuditLogsSince(lastAuditSync);

console.log(`${recentAudits.length} audit entries since last sync`);

getPotentialDuplicates()

getPotentialDuplicates(): Promise<object[]>

Defined in: components/EntityDataManager.ts:823

Retrieves all potential duplicate entity pairs detected by the system.

Returns

Promise<object[]>

Array of entity GUID pairs that are potential duplicates.

Example

const duplicates = await manager.getPotentialDuplicates();

if (duplicates.length > 0) {
console.log(`Found ${duplicates.length} potential duplicate pairs`);

for (const pair of duplicates) {
const entity1 = await manager.getEntity(pair.entityGuid);
const entity2 = await manager.getEntity(pair.duplicateGuid);

console.log('Potential duplicate:');
console.log('Entity 1:', entity1.modified.data);
console.log('Entity 2:', entity2.modified.data);

// TODO: Implement duplicate resolution workflow
}
}

syncWithExternalSystem()

syncWithExternalSystem(credentials?, options?): Promise<SyncResult | undefined>

Defined in: components/EntityDataManager.ts:850

Synchronizes data with external systems (e.g., OpenSPP, custom APIs).

Parameters

credentials?

ExternalSyncCredentials

Optional credentials for external system authentication.

options?

SyncOptions

Returns

Promise<SyncResult | undefined>

Throws

When external sync fails or credentials are invalid.

Example

// Sync with OpenSPP system
try {
await manager.syncWithExternalSystem({
username: 'sync_user',
password: 'sync_password'
});
console.log('External sync completed');
} catch (error) {
console.error('External sync failed:', error.message);
}

// Sync without credentials (if configured in adapter)
await manager.syncWithExternalSystem();

login()

login(credentials, type?): Promise<void>

Defined in: components/EntityDataManager.ts:905

Logs in the user via the configured AuthManager.

Parameters

credentials

The credentials for login.

PasswordCredentials | TokenCredentials | null

type?

string

Optional. The type of authentication provider to use.

Returns

Promise<void>

A Promise that resolves when the login operation is complete.

Throws

If AuthManager is not configured or login fails.


initializeAuthManager()

initializeAuthManager(): Promise<void>

Defined in: components/EntityDataManager.ts:917

Initializes the AuthManager.

Returns

Promise<void>

A Promise that resolves when the AuthManager is initialized.

Throws

If AuthManager is not configured.


logout()

logout(): Promise<void>

Defined in: components/EntityDataManager.ts:929

Logs out the user via the configured AuthManager.

Returns

Promise<void>

A Promise that resolves when the logout operation is complete.

Throws

If AuthManager is not configured or logout fails.


validateToken()

validateToken(type, token): Promise<boolean>

Defined in: components/EntityDataManager.ts:943

Validates an authentication token via the configured AuthManager.

Parameters

type

string

The type of authentication provider.

token

string

The token string to validate.

Returns

Promise<boolean>

A Promise that resolves to true if the token is valid, false otherwise.

Throws

If AuthManager is not configured.


isAuthenticated()

isAuthenticated(): Promise<boolean>

Defined in: components/EntityDataManager.ts:956

Checks if the user is authenticated via the configured AuthManager.

Returns

Promise<boolean>

A Promise that resolves to true if authenticated, false otherwise.

Throws

If AuthManager is not configured.


handleCallback()

handleCallback(type): Promise<void>

Defined in: components/EntityDataManager.ts:970

Handles the authentication callback via the configured AuthManager.

Parameters

type

string

The type of authentication provider.

Returns

Promise<void>

A Promise that resolves when the callback is handled.

Throws

If AuthManager is not configured.