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:
| Parameter | Type | Required | Description |
|---|---|---|---|
tenantId | string | No | Farseer tenant identifier. Falls back to TENANT_ID env var |
apiKey | string | No | API key for authentication. Falls back to FARSEER_API_KEY env var |
basePath | string | No | Server URL. Falls back to FARSEER_URL env var |
config | ConfigurationParameters | No | Full 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>
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Variable 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>
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Dimension 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>
| Parameter | Type | Required | Description |
|---|---|---|---|
dimensionTableName | string | Yes | Parent dimension table name |
dimensionMemberName | string | Yes | Member 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>
| Parameter | Type | Required | Description |
|---|---|---|---|
path | string[] | Yes | Array 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>
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Import job title |
columns | ImportMetadataColumn[] | No | Simplified column definitions (recommended) |
metadata | ImportJobMetadata | No | Full metadata (advanced, alternative to columns) |
description | string | No | Job description |
labels | string[] | No | Labels 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[]>
| Parameter | Type | Required | Description |
|---|---|---|---|
folderInfo | string | number | Yes | Folder name or ID |
fileName | string | Yes | File name |
readHiddenSheets | boolean | No | When 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)
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>
| Parameter | Type | Required | Description |
|---|---|---|---|
mappings | { dimensionTable, from, to }[] | Yes | Dimension member mappings (source → target) |
filters | Record<string, string[]> | No | Filter by dimension table name → member names |
variables | string[] | No | Only copy these variables (by name) |
skipVariables | string[] | No | Skip these variables (by name) |
skipZeros | boolean | No | Skip cells with zero values |
clearData | boolean | No | Clear 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.
Leaf positions inside the target selector that the source has no value for are cleared, not left
alone. Copying Versions>Actual → Versions>Plan for Y2024 wipes any Plan value in Y2024 that
Actual does not cover.
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).
| Copy | Clearing persists? |
|---|---|
sourceVariable and targetVariable are the same — as in the first example above, and in most version-to-version planning copies | No |
sourceFormula mentions the target variable anywhere, including a branch that never evaluates | No |
sourceFormula reaches the target only through a calculated variable's formula | Yes |
| Source and target are unrelated variables | Yes |
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")',
},
],
});
| Parameter | Type | Required | Description |
|---|---|---|---|
filters | [string, string][] | Yes | Named filter expressions usable from the selectors, e.g. [['C0', 'and(Y2026,Forecast)']]. Pass [] if unused. |
cellCopies | { source, target }[] | Yes | One 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 (Sales → Sales, Costs → Costs), so their clearing of uncovered target
positions will not survive a model reload.
lockCells(lockItems)
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)
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:
| Module | Purpose | Example |
|---|---|---|
client.users | User management | client.users.list() |
client.userGroups | User group management | client.userGroups.list() |
client.entities | Entity operations | client.entities.getMany() |
client.evaluator | Formula evaluation | client.evaluator.evaluate() |
client.export | Data export | client.export.exportFormula() |
client.importJobs | Import job operations | client.importJobs.list() |
client.cells | Cell operations | client.cells.calculateOnDemandCells() |
client.folders | Folder management | client.folders.list() |
client.farseerFiles | File operations | client.farseerFiles.get() |
client.sheets | Sheet management | client.sheets.list() |
client.sheetRows | Sheet row operations | client.sheetRows.list() |
client.dashboards | Dashboard management | client.dashboards.list() |
client.shares | Sharing/access control | client.shares.list() |
client.permissions | Permission management | client.permissions.search() |
client.model | Model operations | client.model.load() |
client.versions | Version management | client.versions.list() |
client.timePoints | Time point operations | client.timePoints.list() |
client.labels | Label management | client.labels.list() |
client.assignments | Assignment workflows | client.assignments.list() |
client.assignmentLabels | Assignment labels | client.assignmentLabels.list() |
client.chat | AI chat | client.chat.askAI() |
client.messageThreads | Messaging | client.messageThreads.list() |
client.remoteJobs | Remote job execution | client.remoteJobs.list() |
client.remoteJobRuns | Remote job runs | client.remoteJobRuns.list() |
client.forecastJobs | Forecast operations | client.forecastJobs.search() |
client.auditLogs | Audit trail | client.auditLogs.search() |
client.settings | System settings | client.settings.list() |
client.apiKeys | API key management | client.apiKeys.create() |
client.exportConfigurations | Export configs | client.exportConfigurations.list() |
client.maintenance | System maintenance | client.maintenance.run() |
client.gateway | Gateway operations | client.gateway.run() |
client.engine | Engine operations | client.engine.checkExpression() |
client.backprop | Back-propagation operations | client.backprop.* |
client.customerSupport | Customer support | client.customerSupport.* |
client.keycloakConfigurations | SSO/Keycloak config | client.keycloakConfigurations.* |
client.overseer | System monitoring | client.overseer.* |
client.userActivity | User activity tracking | client.userActivity.* |
Static Properties
FarseerClient.IMPORT_JOB_ROW_BATCH_SIZE = 500; // Default batch size for import rows