Skip to main content

FarseerClient

The main class for interacting with the Farseer API. Extends RawFarseerClient (auto-generated) with high-level convenience methods.

Constructor

new FarseerClient()
new FarseerClient(tenantId: string)
new FarseerClient(tenantId: string, apiKey: string)
new FarseerClient(tenantId: string, apiKey: string, basePath: string)
new FarseerClient(config: ConfigurationParameters)

Parameters:

ParameterTypeRequiredDescription
tenantIdstringNoFarseer tenant identifier. Falls back to TENANT_ID env var
apiKeystringNoAPI key for authentication. Falls back to FARSEER_API_KEY env var
basePathstringNoServer URL. Falls back to FARSEER_URL env var
configConfigurationParametersNoFull configuration object

Example:

// Auto-configuration from environment variables
const client = new FarseerClient();

// Manual configuration
const client = new FarseerClient('my-tenant', 'my-api-key', 'https://app.farseer.io');

// Advanced configuration
const client = new FarseerClient({
basePath: 'https://app.farseer.io/api/v3',
headers: { 'X-TENANT-ID': 'my-tenant', 'X-API-KEY': 'my-api-key' },
});

Tag Management

initTagMap()

Loads all variables, dimension tables, and dimension members into an in-memory lookup map. Must be called before using tag-related methods.

initTagMap(): Promise<TagMaps>

Returns: TagMaps object with lookup maps.

await client.initTagMap();
// Now you can use getVariable(), getDimensionTable(), etc.

getVariable(name)

Retrieves a variable entity by name.

getVariable(name: string): Promise<TagRepresentation>
ParameterTypeRequiredDescription
namestringYesVariable name (case-sensitive)

Returns: TagRepresentation with variable metadata.

const revenue = await client.getVariable('Revenue');
console.log(revenue.id); // 42
console.log(revenue.type); // "ACCOUNT"
console.log(revenue.dataType); // "Decimal"
console.log(revenue.expression); // Formula expression
console.log(revenue.dimensionTagIds); // [10, 11, 12]

getDimensionTable(name)

Retrieves a dimension table by name.

getDimensionTable(name: string): Promise<TagRepresentation>
ParameterTypeRequiredDescription
namestringYesDimension table name
const products = await client.getDimensionTable('Products');
console.log(products.id); // 10
console.log(products.type); // "TABLE"

getDimensionMember(dimensionTableName, dimensionMemberName)

Retrieves a specific dimension member.

getDimensionMember(dimensionTableName: string, dimensionMemberName: string): Promise<TagRepresentation>
ParameterTypeRequiredDescription
dimensionTableNamestringYesParent dimension table name
dimensionMemberNamestringYesMember name
const plan = await client.getDimensionMember('Versions', 'Plan');
console.log(plan.id); // 27
console.log(plan.type); // "DIMENSION"

getDimensionMembersForTable(dimensionTableName)

Returns all members of a dimension table.

getDimensionMembersForTable(dimensionTableName: string): Promise<TagRepresentation[]>
const versions = await client.getDimensionMembersForTable('Versions');
versions.forEach(v => console.log(v.name)); // "Actual", "Plan", "Budget"

resolveDimensionMember(member)

Resolves a DimensionMemberType (table name + member name pair) or an existing TagRepresentation to a TagRepresentation. If the input already has an id, it is returned as-is; otherwise getDimensionMember is called.

resolveDimensionMember(member: DimensionMemberType | TagRepresentation): Promise<TagRepresentation>
// From a name pair
const tag = await client.resolveDimensionMember({ tableName: 'Versions', memberName: 'Plan' });

// Already resolved — returned as-is
const same = await client.resolveDimensionMember(tag);

filterDimensionMembers(dimensionMembers, filterDimensionMembers)

Filters dimension members by connected members (OR logic - matches any).

filterDimensionMembers(
dimensionMembers: (DimensionMemberType | TagRepresentation)[],
filterDimensionMembers: (DimensionMemberType | TagRepresentation)[]
): Promise<TagRepresentation[]>

filterDimensionMembersByAll(dimensionMembers, filterDimensionMembers)

Filters dimension members by connected members (AND logic - matches all).

filterDimensionMembersByAll(
dimensionMembers: (DimensionMemberType | TagRepresentation)[],
filterDimensionMembers: (DimensionMemberType | TagRepresentation)[]
): Promise<TagRepresentation[]>

getDimensionMemberAncestors(member, depth?)

Returns ancestor members in the hierarchy.

getDimensionMemberAncestors(
member: TagRepresentation,
depth?: number
): Promise<TagRepresentation[]>

getDimensionMemberDescendants(member, depth?)

Returns descendant members in the hierarchy.

getDimensionMemberDescendants(
member: TagRepresentation,
depth?: number
): Promise<TagRepresentation[]>

clearTagMap()

Clears the in-memory tag map. Call initTagMap() again to reload.

client.clearTagMap();

Folder Navigation

getItemByPath(path)

Navigates the folder structure and retrieves an item by path.

getItemByPath(path: string[]): Promise<FolderItemRepresentation>
ParameterTypeRequiredDescription
pathstring[]YesArray of folder/file names from root
const file = await client.getItemByPath(['Finance', 'Reports', 'data.xlsx']);
console.log(file.id); // 123
console.log(file.reference); // UUID reference for file download

findItemNode(itemNodeName, itemNodeType)

Finds an item node by name and type.

findItemNode(itemNodeName: string, itemNodeType: FolderItemType): Promise<FolderItemRepresentation>
const folder = await client.findItemNode('Reports', FolderItemType.Folder);

getFolderItems(folderInfo)

Gets all items in a folder.

getFolderItems(folderName: string): Promise<FolderItemRepresentation[]>
getFolderItems(folderId: number): Promise<FolderItemRepresentation[]>

getFolderItem(folderInfo, itemName)

Gets a specific item in a folder by name.

getFolderItem(folderName: string, itemName: string): Promise<FolderItemRepresentation>
getFolderItem(folderId: number, itemName: string): Promise<FolderItemRepresentation>

Import Operations

createImportJob(config)

Creates an import job with simplified column configuration.

createImportJob(config: {
title: string;
columns?: ImportMetadataColumn[];
metadata?: ImportJobMetadata;
description?: string;
labels?: string[];
}): Promise<ImportActions>
ParameterTypeRequiredDescription
titlestringYesImport job title
columnsImportMetadataColumn[]NoSimplified column definitions (recommended)
metadataImportJobMetadataNoFull metadata (advanced, alternative to columns)
descriptionstringNoJob description
labelsstring[]NoLabels for job identification and undoPrevious()

Column types:

type ImportMetadataColumn =
| { type: 'DIMENSION_TABLE'; dimensionTableName: string; columnName?: string }
| { type: 'VARIABLE'; variableName: string; dimensionsNames?: string[]; columnName?: string }
| { type: 'DATE'; dateFormat: string; columnName?: string }
| { type: 'DESCRIPTION'; columnName?: string }
| { type: 'CUSTOM'; columnName: string }
| { type: 'NONE'; columnName?: string };

Returns: ImportActions object.

const importJob = await client.createImportJob({
title: 'Revenue Import Q1',
columns: [
{ type: 'DIMENSION_TABLE', dimensionTableName: 'Products' },
{ type: 'DIMENSION_TABLE', dimensionTableName: 'Years' },
{ type: 'DIMENSION_TABLE', dimensionTableName: 'Months' },
{ type: 'VARIABLE', variableName: 'Revenue' },
],
labels: ['auto', 'revenue', 'Q1-2024']
});

await importJob.addRows([
['Product A', 'Y2024', 'January', 100000],
['Product A', 'Y2024', 'February', 120000],
]);
await importJob.flushRows();
await importJob.undoPrevious();
await importJob.commit();

buildImportJobMetadata(columns)

Builds import job metadata from simplified column definitions. Used internally by createImportJob.

buildImportJobMetadata(columns: ImportMetadataColumn[]): Promise<ImportJobMetadata>

File Operations

createOrUpdateFarseerFile(fileInfo, data)

Creates or updates a file in Farseer. Supports two overloads:

// Overload 1: Create or update by name and folder ID
createOrUpdateFarseerFile(
fileInfo: { name: string; folderId: number },
data: Buffer | Blob
): Promise<void>

// Overload 2: Update an existing folder item
createOrUpdateFarseerFile(
fileItem: FolderItemRepresentation,
data: Buffer | Blob
): Promise<void>

createExcelWorkbookFromFarseerFile(folderInfo, fileName)

Downloads a Farseer file and returns it as an ExcelJS workbook.

createExcelWorkbookFromFarseerFile(
folderInfo: string | number,
fileName: string
): Promise<exceljs.Workbook>

readExcelWorksheetsFromFarseerFile(folderInfo, fileName, readHiddenSheets?)

Reads Excel worksheets as parsed data.

readExcelWorksheetsFromFarseerFile(
folderInfo: string | number,
fileName: string,
readHiddenSheets?: boolean
): Promise<ParsedWorksheetData[]>
ParameterTypeRequiredDescription
folderInfostring | numberYesFolder name or ID
fileNamestringYesFile name
readHiddenSheetsbooleanNoWhen true, includes hidden worksheets in the result

Data Operations

evaluatorExport(exportConfiguration)

Exports data using the evaluator engine. Returns a Blob of CSV or JSON data.

evaluatorExport(exportConfiguration: ExportConfiguration): Promise<Blob>

See ExportConfiguration for the configuration format.

copyAllCells(config)

Not implemented

This wraps client.cells.copyAllCells (POST /cells/copyAll), which responds 501 Not Implemented. For a scope-to-scope copy use copyCells instead, one call per variable.

Copies all cells matching dimension mappings with optional filters. Resolves names to IDs automatically.

copyAllCells(config: {
mappings: { dimensionTable: string; from: string; to: string }[];
filters?: Record<string, string[]>;
variables?: string[];
skipVariables?: string[];
skipZeros?: boolean;
clearData?: boolean;
}): Promise<void>
ParameterTypeRequiredDescription
mappings{ dimensionTable, from, to }[]YesDimension member mappings (source → target)
filtersRecord<string, string[]>NoFilter by dimension table name → member names
variablesstring[]NoOnly copy these variables (by name)
skipVariablesstring[]NoSkip these variables (by name)
skipZerosbooleanNoSkip cells with zero values
clearDatabooleanNoClear target cells before copying
await client.copyAllCells({
mappings: [
{ dimensionTable: 'Versions', from: 'Actual', to: 'Plan' },
],
filters: { 'Years': ['Y2024'] },
skipZeros: true,
});

copyCells(config)

Copies cells from a source variable or formula to a target variable. No sheet required — both ends are addressed in model coordinates. Supports two overloads:

// Overload 1: Copy from a source variable with optional filters
copyCells(config: {
sourceVariable: string;
sourceFilters?: Record<string, string>;
targetVariable: string;
targetFilters?: Record<string, string>;
}): Promise<void>

// Overload 2: Copy from an evaluator formula
copyCells(config: {
sourceFormula: string;
targetVariable: string;
targetFilters?: Record<string, string>;
}): Promise<void>
// Copy variable to variable
await client.copyCells({
sourceVariable: 'Revenue',
sourceFilters: { 'Versions': 'Actual' },
targetVariable: 'Revenue',
targetFilters: { 'Versions': 'Plan' },
});

// Copy formula result to variable
await client.copyCells({
sourceFormula: 'sum("Revenue", "Y2024")',
targetVariable: 'Revenue Target',
targetFilters: { 'Versions': 'Plan' },
});

Selectors may sit above leaf grain — you address Versions>Plan and the source's leaf shape (products, months, …) is reproduced on the target.

The target region is replaced, not merged

Leaf positions inside the target selector that the source has no value for are cleared, not left alone. Copying Versions>ActualVersions>Plan for Y2024 wipes any Plan value in Y2024 that Actual does not cover.

Known limitation — the clearing is not always persisted

Whenever the source expression directly references the destination variable, the clearing described above is applied in memory but not persisted. The affected positions read as empty for the rest of the session, then reappear with their previous values after the next model reload (a Refresh Data, a deploy, any cache invalidation).

CopyClearing persists?
sourceVariable and targetVariable are the same — as in the first example above, and in most version-to-version planning copiesNo
sourceFormula mentions the target variable anywhere, including a branch that never evaluatesNo
sourceFormula reaches the target only through a calculated variable's formulaYes
Source and target are unrelated variablesYes

It is the reference that matters, not whether the value is read — if(1, sum(Volume), sum(VolumeOut)) copied into VolumeOut is affected even though the VolumeOut branch never runs.

Until this is fixed, treat an affected copy as overwriting only the positions the source actually covers. If you need stale target values gone, clear them explicitly with client.model.updateCells (value null) before or after the copy.

A copy is a write: it needs the same CLASS.MODEL.EDIT permission as updateCells and honours the same global locks. Writing into a locked cell fails the whole call rather than partially applying. A copy cannot be undone — unlike updateCells, the engine records no inverse for it.

For batching several copies into one call, or for passing raw RQL on both ends, use client.model.copyCells directly.

client.model.copyCells

The underlying model-level endpoint (POST /model/copyCells). Same addressing model as client.model.updateCells: an RQL expression per end, plus optional named filter expressions.

await client.model.copyCells({
filters: [],
cellCopies: [
{
source: 'sum("Sales", "Versions">"Forecast_prev", "Years">"Y2026")',
target: 'sum("Sales", "Versions">"Forecast", "Years">"Y2026")',
},
{
source: 'sum("Costs", "Versions">"Forecast_prev", "Years">"Y2026")',
target: 'sum("Costs", "Versions">"Forecast", "Years">"Y2026")',
},
],
});
ParameterTypeRequiredDescription
filters[string, string][]YesNamed filter expressions usable from the selectors, e.g. [['C0', 'and(Y2026,Forecast)']]. Pass [] if unused.
cellCopies{ source, target }[]YesOne or more copies, applied in a single engine command

All copies in one call succeed or fail together, and none of them can be undone.

The clearing limitation applies here too, and source being raw RQL makes it easier to hit: any source that names the target's variable is affected. Both copies in the example above do (SalesSales, CostsCosts), so their clearing of uncovered target positions will not survive a model reload.

lockCells(lockItems)

Deprecated

This method throws an error. Locks have been upgraded — use client.settings.getGlobalLocks() and client.settings.setGlobalLocks(lockRules) instead.

lockCells(lockItems: FarseerLockItem[]): Promise<void>

unlockCells(lockItems)

Deprecated

This method throws an error. Locks have been upgraded — use client.settings.getGlobalLocks() and client.settings.setGlobalLocks(lockRules) instead.

unlockCells(lockItems: FarseerLockItem[]): Promise<void>

warmupCache(timeoutMinutes?)

Warms up the server-side cache.

warmupCache(timeoutMinutes?: number): Promise<void>

Utility Methods

getInternalTagType(tagName)

Returns the internal tag type for built-in dimension tables (Years, Quarters, Half Years, Months, Versions, Year to Date). Returns null for custom dimension tables.

getInternalTagType(tagName: string): InternalTagType | null
client.getInternalTagType('Years');    // InternalTagType.Year
client.getInternalTagType('Months'); // InternalTagType.Month
client.getInternalTagType('Products'); // null (custom table)

mapEntityToTag(entity, parentEntity?)

Maps a raw Entity (from the REST API) to a TagRepresentation. Used internally by initTagMap.

mapEntityToTag(entity: Entity, parentEntity?: Entity): TagRepresentation

Generated API Modules

The client exposes all auto-generated API modules as properties. Each module corresponds to a group of REST endpoints:

ModulePurposeExample
client.usersUser managementclient.users.list()
client.userGroupsUser group managementclient.userGroups.list()
client.entitiesEntity operationsclient.entities.getMany()
client.evaluatorFormula evaluationclient.evaluator.evaluate()
client.exportData exportclient.export.exportFormula()
client.importJobsImport job operationsclient.importJobs.list()
client.cellsCell operationsclient.cells.calculateOnDemandCells()
client.foldersFolder managementclient.folders.list()
client.farseerFilesFile operationsclient.farseerFiles.get()
client.sheetsSheet managementclient.sheets.list()
client.sheetRowsSheet row operationsclient.sheetRows.list()
client.dashboardsDashboard managementclient.dashboards.list()
client.sharesSharing/access controlclient.shares.list()
client.permissionsPermission managementclient.permissions.search()
client.modelModel operationsclient.model.load()
client.versionsVersion managementclient.versions.list()
client.timePointsTime point operationsclient.timePoints.list()
client.labelsLabel managementclient.labels.list()
client.assignmentsAssignment workflowsclient.assignments.list()
client.assignmentLabelsAssignment labelsclient.assignmentLabels.list()
client.chatAI chatclient.chat.askAI()
client.messageThreadsMessagingclient.messageThreads.list()
client.remoteJobsRemote job executionclient.remoteJobs.list()
client.remoteJobRunsRemote job runsclient.remoteJobRuns.list()
client.forecastJobsForecast operationsclient.forecastJobs.search()
client.auditLogsAudit trailclient.auditLogs.search()
client.settingsSystem settingsclient.settings.list()
client.apiKeysAPI key managementclient.apiKeys.create()
client.exportConfigurationsExport configsclient.exportConfigurations.list()
client.maintenanceSystem maintenanceclient.maintenance.run()
client.gatewayGateway operationsclient.gateway.run()
client.engineEngine operationsclient.engine.checkExpression()
client.backpropBack-propagation operationsclient.backprop.*
client.customerSupportCustomer supportclient.customerSupport.*
client.keycloakConfigurationsSSO/Keycloak configclient.keycloakConfigurations.*
client.overseerSystem monitoringclient.overseer.*
client.userActivityUser activity trackingclient.userActivity.*

Static Properties

FarseerClient.IMPORT_JOB_ROW_BATCH_SIZE = 500; // Default batch size for import rows