Appearance
Program Spreadsheet
Read a building's program and takeoff data and render, build, format, and export report sheets from it. The surface spans two levels: high-level renders (render, renderTakeoff, renderProgram) that produce a formatted, titled table in one call, and low-level construction (createSheet, setValues, setFormulas, …) for authors who need fine control. Accessed via snaptrude.program.spreadsheet.
All methods are host API calls that return Promises. Reads return a snapshot of the current workbook or dataset. render and templates.apply create-or-replace their target sheet; createSheet reuses an existing sheet of the same name by default. transaction is the atomic batch — its operations commit together and undo as a single step.
Program tab required
The report workbook lives in the Program tab. Every method in this namespace needs it open and fails fast with "The Program/Sheets view is not open" otherwise — except getProgram(), getTakeoff(), and getMaterialTakeoff(), which read the dataset natively from the editor and work with the tab closed. (renderTakeoff/renderProgram still need the tab — they render to the workbook.)
At a glance
| Method | What it does | Mutates? |
|---|---|---|
| Read data | ||
listSheets() | List the workbook's sheets and the active sheet | — |
getSheetData(sheetName, options?) | Read a sheet back as a values matrix (and optional records) | — |
getProgram() | Read the area-program dataset (target vs allocated per department) | — |
getTakeoff() | Read the quantity/material takeoff dataset | — |
getMaterialTakeoff() | Read the material take-off dataset (surface area per material) | — |
getAuditLog(options?) | Read the recent operations performed through this API | — |
ping() | Check the program-mode spreadsheet bridge is reachable | — |
| Render reports | ||
render(sheetName, columns, rows, options?) | Render a titled, formatted table onto a sheet (create-or-replace) | ✓ |
renderTakeoff(options?) | Render the current takeoff dataset onto a sheet | ✓ |
renderProgram(options?) | Render the current area program onto a sheet | ✓ |
export(format, options?) | Export to xlsx/pdf (whole workbook) or csv (one sheet) as base64 | — |
| Build cells | ||
createSheet(name, whenExists?) | Create (or reuse/replace) a named sheet | ✓ |
setValues(sheetName, values, startCell?) | Write a matrix of raw values anchored at a cell | ✓ |
setFormulas(sheetName, formulas) | Set formulas on individual cells | ✓ |
mergeCells(sheetName, range, value?) | Merge a range into one spanned cell | ✓ |
| Format | ||
setStyles(sheetName, ranges) | Apply cell styles to one or more ranges | ✓ |
addConditionalFormatting(sheetName, range, rule) | Add a conditional-formatting rule (data bars) to a range | ✓ |
highlightCells(sheetName, range, options?) | Highlight a range (background color, optional bold) | ✓ |
addChart(sheetName, chartType, dataRange, options?) | Add a chart driven by a cell range | ✓ |
recalculate(options?) | Recompute the workbook's formula results | ✓ |
| Batch & advanced | ||
transaction(operations, label?) | Run construction ops as one atomic, undoable batch | ✓ |
runScript(script) | Run a script against a sandboxed workbook facade | Script-dependent |
| Templates | ||
templates.create(name, sheetName, scope?) | Save a sheet's layout as a named template | ✓ |
templates.apply(name, targetSheetName) | Apply a saved template to a target sheet (create-or-replace) | ✓ |
| Bindings | ||
bindings.create(name, source, target, mode?) | Bind a dataset to a sheet range (with an initial refresh) | ✓ |
bindings.refresh(options?) | Re-pull one binding's (or every binding's) source data | ✓ |
bindings.list() | List all stored data bindings | — |
Types
PluginSpreadsheetCell
A single cell value: string | number | boolean | null. Cell matrices (values) are row-major arrays of these; row records map column keys to them.
PluginSpreadsheetColumn
A column definition for render.
| Property | Type | Description |
|---|---|---|
key | string | Key into each row object |
header | string | Column header text |
width | number? | Fixed column width in px; auto-fit when omitted |
format | string? | Number/date format string applied to the data cells |
align | "left" | "center" | "right"? | Cell alignment |
PluginSpreadsheetTotal
A totals-row aggregation for render.
| Property | Type | Description |
|---|---|---|
column | string | The PluginSpreadsheetColumn key to aggregate |
fn | "sum" | "avg" | "count" | "min" | "max" | Aggregation function |
label | string? | Optional label printed in the first column of the totals row |
PluginProgramSpreadsheetRenderResult
The rendered-artifact record returned by render, renderTakeoff, and renderProgram.
| Property | Type | Description |
|---|---|---|
sheetName | string | The sheet that was written |
range | string | A1 range covering the full written block (title + header + data + totals) |
headerRange | string | A1 range of the header row alone |
rowCount | number | Number of data rows written (excludes title/header/totals) |
colCount | number | Number of columns written |
tableName | string | null | The created table's name, or null when not wrapped as a table |
replaced | boolean | Whether an existing sheet was replaced |
PluginSpreadsheetSheetInfo
Metadata for one sheet in the listSheets result.
| Property | Type | Description |
|---|---|---|
name | string | Sheet name |
index | number | Zero-based sheet index |
visible | boolean | Whether the sheet is visible |
rowCount | number | Total rows in the sheet |
colCount | number | Total columns in the sheet |
PluginSpreadsheetProgramRow
One department row in the area-program dataset. Areas are in the enclosing result's units.
| Property | Type | Description |
|---|---|---|
departmentId | string | Department id |
name | string | Department name |
targetArea | number | null | Target area, or null if no target is set |
allocatedArea | number | Area currently allocated to this department |
variance | number | null | allocatedArea − targetArea, or null when no target |
PluginSpreadsheetTakeoffRow
One family-aggregated row in the quantity/material takeoff dataset. The takeoff is grouped by object type + category + family (not per element), so each row is a rolled-up quantity for that family.
| Property | Type | Description |
|---|---|---|
objectType | string | Element object type (e.g. "Wall", "Door", "Window") |
category | string | Element category |
family | string | Element family the quantity is aggregated over |
quantity | number | Aggregated quantity in unit |
unit | string | Quantity unit (e.g. "m" for length, "m2" for area) |
PluginSpreadsheetMaterialTakeoffRow
One row in the material take-off dataset. Grouped by object type + family + applied material, so each row is a rolled-up surface area for that material on that family.
| Property | Type | Description |
|---|---|---|
objectType | string | Element object type the material sits on ("wall", "floor", "ceiling", "slab", "roof") |
family | string | Element family the quantity is aggregated under |
material | string | Applied material name |
quantity | number | Rolled-up surface area in unit |
unit | string | Area unit (e.g. "sq.ft" or "sq.m") |
PluginSpreadsheetFormula
A single cell formula for setFormulas.
| Property | Type | Description |
|---|---|---|
cell | string | Target cell in A1 notation |
formula | string | Formula expression (a leading = is optional) |
PluginSpreadsheetCellStyle
A cell style for setStyles. All fields are optional; only the ones provided are applied.
| Property | Type | Description |
|---|---|---|
backColor | string? | Background (fill) color, CSS hex |
foreColor | string? | Text color, CSS hex |
font | string? | Full CSS font shorthand (overrides the parts below) |
fontFamily | string? | Font family |
fontSize | number? | Font size in px |
fontWeight | "normal" | "bold"? | Font weight |
fontStyle | "normal" | "italic"? | Font style |
formatter | string? | Number/date format string |
horizontalAlign | "left" | "center" | "right" | "general"? | Horizontal alignment |
verticalAlign | "top" | "center" | "bottom"? | Vertical alignment |
PluginSpreadsheetRangeStyle
A range + the style to apply to it, for setStyles.
| Property | Type | Description |
|---|---|---|
range | string | A1 range to style |
style | PluginSpreadsheetCellStyle | The style to apply |
PluginSpreadsheetConditionalRule
A conditional-formatting rule for addConditionalFormatting. Currently only dataBar; more rule types are reserved.
| Property | Type | Description |
|---|---|---|
type | "dataBar" | The rule kind (a proportional in-cell bar) |
color | string? | Bar color, CSS hex (a default is used when omitted) |
PluginSpreadsheetTransactionOp
One operation within a transaction.
| Property | Type | Description |
|---|---|---|
method | "createSheet" | "setValues" | "setFormulas" | "setStyles" | "mergeCells" | The batchable method to run |
args | unknown | The method's own arguments object |
PluginSpreadsheetAuditEntry
One entry in the program-spreadsheet audit log.
| Property | Type | Description |
|---|---|---|
id | string | Entry id |
pluginId | string | Id of the plugin that performed the operation |
method | string | The API method invoked |
label | string? | Optional operation label |
sheetName | string? | The sheet the operation targeted, if any |
timestamp | string | ISO timestamp |
status | "success" | "error" | Whether the operation succeeded |
summary | string? | Short human-readable summary |
PluginSpreadsheetBinding
A stored data binding.
| Property | Type | Description |
|---|---|---|
id | string | Binding id |
name | string | Binding name (unique per workbook) |
pluginId | string | Id of the plugin that owns the binding |
source | { dataset: "takeoff" } | The bound dataset |
target | { sheetName: string; startCell: string } | The resolved target range anchor |
mode | "replaceRange" | How a refresh writes into the target |
createdAt | string | ISO creation timestamp |
updatedAt | string | ISO last-refresh timestamp |
PluginSpreadsheetBindingRefresh
The outcome of refreshing a single binding.
| Property | Type | Description |
|---|---|---|
id | string | The refreshed binding's id |
name | string | The refreshed binding's name |
sheetName | string | The sheet that was rewritten |
rowCount | number | Number of rows written |
Functions
render(sheetName, columns, rows, options?)
Render a titled, formatted table onto a named sheet (create-or-replace). The intent-level replacement for the raw cell-write sequence: it writes the header + rows, applies per-column format/alignment, optionally wraps the block in a table, freezes the header, and appends a totals row.
- Parameters:
sheetName:string— target sheet namecolumns:PluginSpreadsheetColumn[]— column definitions (at least one)rows:Record<string, PluginSpreadsheetCell>[]— row objects keyed by columnkeyoptions.title:string | undefined— title rendered above the headeroptions.startCell:string | undefined— top-left anchor in A1 notation (default"A1")options.whenExists:"replace" | "error" | undefined— behaviour if the sheet exists (default"replace")options.asTable:boolean | undefined— wrap the block in a table (defaulttrue)options.freezeHeader:boolean | undefined— freeze rows above the data (defaulttrue)options.totals:PluginSpreadsheetTotal[] | undefined— optional totals row
- Returns:
PluginProgramSpreadsheetRenderResult— the written ranges and counts. - Throws: If
columnsis empty, the target sheet exists andwhenExistsis"error", or a cell address is invalid.
ts
const result = await snaptrude.program.spreadsheet.render(
"Program",
[
{ key: "name", header: "Department" },
{ key: "area", header: "Area", format: "0.00", align: "right" }
],
[
{ name: "FOH", area: 120.5 },
{ name: "BOH", area: 86.25 }
],
{
title: "Program Summary",
totals: [{ column: "area", fn: "sum", label: "Total" }]
}
);
console.log(result.range, result.rowCount);renderTakeoff(options?)
Render the quantity/material takeoff onto a sheet. The host pulls and projects the current takeoff dataset itself — the plugin supplies only the target sheetName, an optional title, and an optional filter; there is no data argument.
- Parameters:
options.sheetName:string | undefined— target sheet name (a default is used when omitted)options.title:string | undefined— title rendered above the tableoptions.filter:string | undefined— case-insensitive substring applied host-side; a row is kept when any of its cell values contains it (blank/omitted keeps every row). Not a query language.
- Returns:
PluginProgramSpreadsheetRenderResult— the written ranges and counts. - Throws: If the takeoff cannot be rendered.
ts
const { range, rowCount } = await snaptrude.program.spreadsheet.renderTakeoff({
sheetName: "Takeoff",
title: "Quantity Takeoff",
filter: "wall" // keep only rows whose cells mention "wall"
});
console.log(`Wrote ${rowCount} rows to ${range}`);renderProgram(options?)
Render the area program onto a sheet (departments with area targets vs allocated). The host pulls and projects the current program dataset itself — the plugin supplies only the target sheetName, an optional title, and an optional filter; there is no data argument.
- Parameters:
options.sheetName:string | undefined— target sheet name (a default is used when omitted)options.title:string | undefined— title rendered above the tableoptions.filter:string | undefined— case-insensitive substring applied host-side; a row is kept when any of its cell values contains it (blank/omitted keeps every row). Not a query language.
- Returns:
PluginProgramSpreadsheetRenderResult— the written ranges and counts. - Throws: If the program cannot be rendered.
ts
await snaptrude.program.spreadsheet.renderProgram({ sheetName: "Program" });export(format, options?)
Export the report workbook to a file (xlsx, pdf, or csv). Returns the file content as base64 so the plugin can download, upload, or attach it. This is the workbook file export; to read cell values back as data, use getSheetData instead.
xlsx and pdf export the whole workbook. csv is inherently single-sheet — it serializes one sheet's used range; pass options.sheetName to choose which sheet, or omit it to serialize the active sheet.
- Parameters:
format:"xlsx" | "pdf" | "csv"— the file format to export tooptions.fileName:string | undefined— desired file name (without extension); a default is used when omittedoptions.sheetName:string | undefined— forcsv, the sheet to serialize (the active sheet when omitted); ignored byxlsx/pdf, which always export the whole workbook
- Returns:
{ format: "xlsx" | "pdf" | "csv"; fileName: string; mimeType: string; dataBase64: string }— the exported file. - Throws: If the workbook cannot be serialized to the requested format.
ts
// Whole workbook as xlsx:
const file = await snaptrude.program.spreadsheet.export("xlsx", { fileName: "program-report" });
// Decode the base64 payload into a downloadable Blob
const bytes = Uint8Array.from(atob(file.dataBase64), (c) => c.charCodeAt(0));
const blob = new Blob([bytes], { type: file.mimeType });
const url = URL.createObjectURL(blob);
console.log(file.fileName, url);
// A single sheet as CSV:
const csv = await snaptrude.program.spreadsheet.export("csv", { sheetName: "Takeoff" });
console.log(csv.mimeType); // "text/csv"listSheets()
List the sheets in the report workbook.
- Returns:
{ sheets: PluginSpreadsheetSheetInfo[]; activeSheet: string | null }— each sheet's name/index/visibility/size, plus the active sheet name.
ts
const { sheets, activeSheet } = await snaptrude.program.spreadsheet.listSheets();
for (const s of sheets) console.log(s.name, s.rowCount, s.colCount);
console.log("Active:", activeSheet);getSheetData(sheetName, options?)
Read a sheet's data back as a matrix (and optionally as header-keyed records).
- Parameters:
sheetName:string— sheet to readoptions.range:string | undefined— A1 range; defaults to the sheet's used rangeoptions.header:boolean | undefined— whentrue, also return records keyed by the first (header) row
- Returns:
{ sheetName: string; range: string; values: PluginSpreadsheetCell[][]; records?: Record<string, PluginSpreadsheetCell>[] }—recordsis present only whenheaderwastrue. - Throws: If the sheet does not exist or the range is invalid.
ts
const { values, records } = await snaptrude.program.spreadsheet.getSheetData("Program", {
header: true
});
console.log(values.length, "rows read");
if (records) for (const r of records) console.log(r);addChart(sheetName, chartType, dataRange, options?)
Add a chart to a sheet, driven by a cell range.
- Parameters:
sheetName:string— sheet to add the chart tochartType:"column" | "bar" | "line" | "pie" | "area" | "scatter"— chart typedataRange:string— A1 range driving the chartoptions.title:string | undefined— optional chart titleoptions.position:{ x: number; y: number } | undefined— top-left position (sheet coords)options.size:{ width: number; height: number } | undefined— chart size in px
- Returns:
{ chartId: string }— id of the created chart. - Throws: If the sheet or data range is invalid.
ts
const { chartId } = await snaptrude.program.spreadsheet.addChart("Program", "column", "A1:B10", {
title: "Area by department"
});
console.log(chartId);highlightCells(sheetName, range, options?)
Highlight a range of cells (background color and optional emphasis). For multi-range or richer styling, use setStyles.
- Parameters:
sheetName:string— sheet containing the rangerange:string— A1 range to highlightoptions.color:string | undefined— CSS hex background color (a default emphasis is used when omitted)options.bold:boolean | undefined— also bold the text
- Returns:
{ sheetName: string; range: string }— echoes the highlighted sheet and range. - Throws: If the sheet or range is invalid.
ts
await snaptrude.program.spreadsheet.highlightCells("Program", "A2:A10", {
color: "#ffe08a"
});getProgram()
Read the area-program dataset (departments with target vs allocated area). Returns the same figures renderProgram projects onto a sheet, as render-ready rows — so a plugin can inspect or transform the program before rendering it (or render it itself via render).
- Returns:
{ units: "ft2" | "m2"; rows: PluginSpreadsheetProgramRow[]; totalTargetArea: number; totalAllocatedArea: number; generatedAt: string }— per-department rows, totals, and the report units.
ts
const program = await snaptrude.program.spreadsheet.getProgram();
const over = program.rows.filter((r) => r.variance !== null && r.variance > 0);
console.log(`${over.length} departments over target (${program.units})`);getTakeoff()
Read the quantity/material takeoff dataset. Returns the same rows renderTakeoff projects onto a sheet — one rolled-up record per object-type/category/family group — so a plugin can inspect or transform the takeoff before rendering it.
- Returns:
{ rows: PluginSpreadsheetTakeoffRow[]; rowCount: number; generatedAt: string }— the takeoff rows, a row count, and the read timestamp.
ts
const takeoff = await snaptrude.program.spreadsheet.getTakeoff();
for (const row of takeoff.rows) {
console.log(row.objectType, row.family, row.quantity, row.unit);
}getMaterialTakeoff()
Read the material take-off dataset — the native "Material Take-Off" quantities (the same figures the BIM Take-Off's Material Take-Off sheet lists) as render-ready rows. For each material applied to a wall/floor/ceiling/slab/roof family, its rolled-up surface area in the project's display units. This is the material-centric complement to getTakeoff (which rolls up by element family). A native editor read — it works with the Program tab closed, and writes nothing.
When no materials are applied (or the model is empty), rows is simply an empty array — not an error.
- Returns:
{ rows: PluginSpreadsheetMaterialTakeoffRow[]; rowCount: number; generatedAt: string }— the material take-off rows, a row count, and the read timestamp.
ts
const mto = await snaptrude.program.spreadsheet.getMaterialTakeoff();
for (const row of mto.rows) {
console.log(row.objectType, row.family, row.material, row.quantity, row.unit);
}createSheet(name, whenExists?)
Create (or reuse/replace) a named sheet in the report workbook. The blank-canvas complement to render: use it when you want an empty sheet to write into with setValues / setFormulas. By default an existing sheet of the same name is reused; pass whenExists to replace or error.
- Parameters:
name:string— the sheet name to createwhenExists:"reuse" | "replace" | "error" | undefined— behaviour if the name exists (default"reuse")
- Returns:
{ sheetName: string; replaced: boolean; sheetIndex: number | null }— the resolved name, whether an existing sheet was replaced/cleared, and its zero-based index (nullif unknown). - Throws: If the sheet exists and
whenExistsis"error".
ts
const { sheetName, replaced } = await snaptrude.program.spreadsheet.createSheet(
"Summary",
"replace"
);
console.log(sheetName, replaced ? "(replaced)" : "(new)");setValues(sheetName, values, startCell?)
Write a block of raw values into a sheet, anchored at a cell. The low-level cell-write path (the high-level path is render, which adds a header, format, and totals). Values are written row-major from startCell; columns are auto-sized to fit.
- Parameters:
sheetName:string— sheet to write intovalues:PluginSpreadsheetCell[][]— row-major matrix of values to writestartCell:string | undefined— top-left anchor in A1 notation (default"A1")
- Returns:
{ sheetName: string; startCell: string; rowCount: number; colCount: number }— the anchor and the written block's size. - Throws: If the sheet does not exist or
startCellis invalid.
ts
await snaptrude.program.spreadsheet.setValues(
"Summary",
[
["Department", "Area"],
["FOH", 120.5]
],
"A1"
);setFormulas(sheetName, formulas)
Set formulas on individual cells of a sheet. Each entry targets one cell (A1 notation) with a formula expression (a leading = is optional). Pairs with recalculate when you need to force a recompute.
- Parameters:
sheetName:string— sheet to set formulas onformulas:PluginSpreadsheetFormula[]— the cell → formula assignments
- Returns:
{ sheetName: string; count: number }— the number of formulas set. - Throws: If the sheet does not exist or a cell address is invalid.
ts
await snaptrude.program.spreadsheet.setFormulas("Summary", [
{ cell: "B10", formula: "=SUM(B2:B9)" }
]);setStyles(sheetName, ranges)
Apply cell styles to one or more ranges of a sheet. Sets fill/text color, font, alignment, and number format on each given range. For a quick single-range emphasis, highlightCells is the shortcut.
- Parameters:
sheetName:string— sheet containing the rangesranges:PluginSpreadsheetRangeStyle[]— range → style assignments
- Returns:
{ sheetName: string; count: number }— the number of ranges styled. - Throws: If the sheet does not exist or a range is invalid.
ts
await snaptrude.program.spreadsheet.setStyles("Summary", [
{ range: "A1:D1", style: { fontWeight: "bold", backColor: "#eef" } }
]);mergeCells(sheetName, range, value?)
Merge a contiguous range of cells into a single spanned cell, optionally setting the merged cell's value.
- Parameters:
sheetName:string— sheet containing the rangerange:string— A1 range to merge into one spanned cellvalue:PluginSpreadsheetCell | undefined— optional value to set in the merged (top-left) cell
- Returns:
{ sheetName: string; range: string }— echoes the merged sheet and range. - Throws: If the sheet does not exist or the range is invalid.
ts
await snaptrude.program.spreadsheet.mergeCells("Summary", "A1:D1", "Program Summary");addConditionalFormatting(sheetName, range, rule)
Add a conditional-formatting rule to a range. Currently supports data-bar rules (a proportional in-cell bar); more rule types are reserved. For static (non-conditional) emphasis use highlightCells or setStyles.
- Parameters:
sheetName:string— sheet containing the rangerange:string— A1 range to formatrule:PluginSpreadsheetConditionalRule— the conditional-format rule
- Returns:
{ sheetName: string; range: string; created: boolean }—createdreports whether a data-bar rule was created (vs a fallback fill). - Throws: If the sheet does not exist or the range is invalid.
ts
await snaptrude.program.spreadsheet.addConditionalFormatting("Summary", "B2:B10", {
type: "dataBar",
color: "#4f9cf9"
});recalculate(options?)
Recompute the workbook's formula results. Recalculates every formula (or, when sheetName is given, focuses that sheet before recalculating the workbook). Distinct from bindings.refresh, which re-pulls a binding's source data.
- Parameters:
options.sheetName:string | undefined— a sheet to focus before recalculating; omit for the whole workbook
- Returns:
{ scope: "sheet" | "workbook"; sheetName: string | null }— the recompute scope and the focused sheet (nullfor a workbook-wide recompute).
ts
await snaptrude.program.spreadsheet.recalculate();transaction(operations, label?)
Run a sequence of sheet operations as one atomic, undoable transaction. Batches cell-construction operations (createSheet, setValues, setFormulas, setStyles, mergeCells) so they commit together and undo as a single step, with events suspended for speed.
- Parameters:
operations:PluginSpreadsheetTransactionOp[]— the operations to run in order; each operation'sargsstays that method's schema object (the wire shape), not positionallabel:string | undefined— undo-history label for the batch
- Returns:
{ label: string; operationCount: number; results: unknown[] }— the label used, the number of operations run, and each operation's result in order. - Throws: If any operation names an unsupported method or fails.
ts
const { operationCount } = await snaptrude.program.spreadsheet.transaction(
[
{ method: "createSheet", args: { name: "Summary", whenExists: "replace" } },
{
method: "setValues",
args: {
sheetName: "Summary",
values: [
["Department", "Area"],
["FOH", 120.5]
]
}
},
{
method: "setFormulas",
args: { sheetName: "Summary", formulas: [{ cell: "B3", formula: "=SUM(B2:B2)" }] }
}
],
"Build summary"
);
console.log(`${operationCount} operations committed as one undo step`);runScript(script)
Run an author-supplied script against a sandboxed workbook facade. The escape hatch for advanced automation the typed methods don't cover: the script runs against a restricted workbook object with browser/network globals blocked, and its return value is handed back as result. Prefer the typed methods where they exist.
- Parameters:
script:string— script source, run against the sandboxedworkbookfacade
- Returns:
{ result: unknown }— the script's return value (nullwhen it returns nothing). - Throws: If the script uses a blocked browser/network API or throws at runtime.
ts
const { result } = await snaptrude.program.spreadsheet.runScript(
"return workbook.getSheetCount();"
);
console.log("Sheet count:", result);getAuditLog(options?)
Read the recent audit log of program-spreadsheet operations. Returns the most recent operations performed through this API (method, sheet, status, summary, timestamp), newest first — useful for showing the user what a plugin changed.
- Parameters:
options.limit:number | undefined— max entries to return (clamped 1–100, default 20)
- Returns:
{ entries: PluginSpreadsheetAuditEntry[] }— recent audit entries, newest first.
ts
const { entries } = await snaptrude.program.spreadsheet.getAuditLog({ limit: 10 });
for (const e of entries) console.log(e.timestamp, e.method, e.status, e.summary);ping()
Ping the program-mode spreadsheet bridge to check it is reachable. A liveness probe: resolves with { pong: true } when the program-mode workbook bridge is up.
- Returns:
{ pong: boolean }—truewhen the bridge is reachable.
ts
const { pong } = await snaptrude.program.spreadsheet.ping();
console.log(pong ? "Spreadsheet bridge is up" : "Bridge unreachable");Templates
Reusable sheet templates — capture a sheet's layout as a named template and re-apply it to another sheet. Accessed via snaptrude.program.spreadsheet.templates.
templates.create(name, sheetName, scope?)
Save a sheet's current layout as a named template. Re-saving the same name overwrites it.
- Parameters:
name:string— template name (re-saving the same name overwrites it)sheetName:string— the source sheet to capturescope:"project" | "global" | undefined— template scope (default"project")
- Returns:
{ id: string; name: string; scope: "project" | "global"; sheetName: string }— the new template's id, name, scope, and source sheet. - Throws: If the source sheet does not exist.
ts
const template = await snaptrude.program.spreadsheet.templates.create("Cover", "Summary");
console.log(template.id, template.scope);templates.apply(name, targetSheetName)
Apply a saved template to a target sheet (create-or-replace).
- Parameters:
name:string— the template to applytargetSheetName:string— the sheet to create/replace from the template
- Returns:
{ name: string; targetSheetName: string }— echoes the applied template and target sheet. - Throws: If the named template does not exist.
ts
await snaptrude.program.spreadsheet.templates.apply("Cover", "Report");Bindings
Live data bindings — bind a program dataset to a sheet range so it can be refreshed on demand. A binding links a dataset (currently the takeoff) to a target sheet range; a refresh re-pulls the current data and rewrites the range. Accessed via snaptrude.program.spreadsheet.bindings.
bindings.create(name, source, target, mode?)
Create a named binding from a dataset to a sheet range (and do an initial refresh). Re-using a name overwrites the existing binding.
- Parameters:
name:string— binding name (re-using a name overwrites it)source:{ dataset: "takeoff" }— the dataset to bind (currently only the takeoff;programis reserved for a future source)target:{ sheetName: string; startCell?: string }— the target sheet range (startCelldefaults to"A1")mode:"replaceRange" | undefined— how a refresh writes into the target (default"replaceRange")
- Returns:
PluginSpreadsheetBinding & { refresh: PluginSpreadsheetBindingRefresh }— the stored binding plus therefreshresult of the initial pull. - Throws: If the target sheet does not exist.
ts
const binding = await snaptrude.program.spreadsheet.bindings.create(
"takeoff",
{ dataset: "takeoff" },
{ sheetName: "Data", startCell: "A1" }
);
console.log(binding.id, binding.refresh.rowCount, "rows written");bindings.refresh(options?)
Refresh one binding (by name) or all bindings, re-pulling their source data into their target ranges. Distinct from recalculate, which recomputes formulas.
- Parameters:
options.name:string | undefined— the binding to refresh; omit to refresh every binding
- Returns:
{ refreshed: PluginSpreadsheetBindingRefresh[] }— one entry per binding that was updated. - Throws: If a
nameis given but no binding with that name exists.
ts
const { bindings } = await snaptrude.program.spreadsheet.bindings.list();
if (bindings.length > 0) {
const { refreshed } = await snaptrude.program.spreadsheet.bindings.refresh({
name: bindings[0].name
});
for (const r of refreshed) console.log(r.name, r.rowCount, "rows");
}bindings.list()
List all data bindings in the workbook.
- Returns:
{ bindings: PluginSpreadsheetBinding[] }— every stored binding.
ts
const { bindings } = await snaptrude.program.spreadsheet.bindings.list();
for (const b of bindings) console.log(b.name, b.target.sheetName, b.updatedAt);Errors
Failed calls reject with a typed PluginError — see Error Handling. Conditions specific to this namespace:
| Code | Thrown by | When | details |
|---|---|---|---|
TIMEOUT | every relayed method | The Program-tab round-trip exceeded 15 s (the tab is open but not answering) | timeoutMs |
Workbook-level failures — the Program/Sheets view not being open, a missing sheet or template, whenExists: "error" on an existing sheet, an invalid range/cell address, a blocked runScript API, an unknown binding name — are reported by the spreadsheet side of the bridge and currently surface as INTERNAL (a sanitized message with an errorId; the underlying reason is host-logged), not as a distinct code.
getProgram(), getTakeoff(), and getMaterialTakeoff() are native editor reads: they work with the Program tab closed and have no namespace-specific error conditions.