Spreadsheet-UX op een echte relationele engine
Deze repository wordt als momentopname gepubliceerd: een clone bevat de volledige inhoud, maar geen commitgeschiedenis.
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import Database from 'better-sqlite3';
import { literal, type Member } from '@wellformed/shared';
import type { Db } from '../db/driver.js';
import { newId } from '../engine/ids.js';
export interface WorkspaceSnapshot {
/** The file to stream. Call `dispose` once it has been sent. */
file: string;
dispose(): void;
}
/**
* Write a consistent, self-contained copy of one workspace.
*
* `VACUUM INTO` is the whole trick: SQLite takes the snapshot itself, at a
* single point in time, without blocking writers and without WAL sidecars to
* ship alongside. What comes out is one file that opens in any SQLite tool.
*
* Because identity lives in the control plane, a raw copy would arrive with no
* record of who had access. The roster is written into the copy — never the
* original — as `_wellformed_member`, so the export answers that question on its
* own. Password hashes are deliberately not included: this is a data export,
* not a way to move credentials around.
*/
export function snapshotWorkspace(db: Db, members: Member[]): WorkspaceSnapshot {
const directory = mkdtempSync(path.join(tmpdir(), 'wellformed-export-'));
const file = path.join(directory, `${newId('snap')}.db`);
// VACUUM INTO takes a SQL string literal, not a bound parameter.
db.sqlite.exec(`VACUUM INTO ${literal(file)}`);
const copy = new Database(file);
try {
copy.exec(`
CREATE TABLE _wellformed_member (
id TEXT PRIMARY KEY,
email TEXT NOT NULL,
name TEXT NOT NULL,
role TEXT NOT NULL,
joined_at TEXT,
disabled INTEGER NOT NULL DEFAULT 0
);
`);
const insert = copy.prepare(
'INSERT INTO _wellformed_member (id, email, name, role, joined_at, disabled) VALUES (?, ?, ?, ?, ?, ?)',
);
const writeAll = copy.transaction((rows: Member[]) => {
for (const m of rows) {
insert.run(m.id, m.email, m.name, m.role, m.joinedAt, m.disabled ? 1 : 0);
}
});
writeAll(members);
} finally {
copy.close();
}
return {
file,
dispose: () => rmSync(directory, { recursive: true, force: true }),
};
}
/** `wellformed-acme-2026-08-06.db` — obvious in a downloads folder a year later. */
export function snapshotFilename(slug: string, now = new Date()): string {
const day = now.toISOString().slice(0, 10);
return `wellformed-${slug}-${day}.db`;
}