import type { BackendContext } from '@jaspers-ai/sdk' import { buildXlsx } from './xlsx' import { cleanFilename, defaultFilename, rowArrays, sheetNames } from './sheets' export interface TableInput { title: string columns: string[] rows: unknown[] } function base64(bytes: Uint8Array): string { let s = '' for (let i = 0; i < bytes.length; i += 0x8000) s += String.fromCharCode(...bytes.subarray(i, i + 0x8000)) return btoa(s) } /** Builds the workbook, writes it under exports/, opens it, and answers path, sheets, and row counts. */ export async function writeWorkbook(ctx: BackendContext, tables: TableInput[], filename?: string) { if (tables.length === 0) throw new Error('No tables to export.') const names = sheetNames(tables.map((t) => t.title)) const sheets = tables.map((t, i) => ({ name: names[i]!, columns: t.columns, rows: rowArrays(t.columns, t.rows) })) const file = filename ? cleanFilename(filename) : defaultFilename(tables[0]!.title, new Date()) const path = `exports/${file}` await ctx.files.write(path, base64(buildXlsx(sheets)), { encoding: 'base64' }) let opened = true try { await ctx.files.open(path) } catch { opened = false } return { path, location: `~/Jaspers/excel-export/${path}`, opened, sheets: sheets.map((s) => s.name), rows: sheets.map((s) => ({ sheet: s.name, title: tables[sheets.indexOf(s)]!.title, rows: s.rows.length, columns: s.columns.length })), } }