Implements docs/sendoff.md's v2: a folder convention, one endpoint and a push. No staging area, no transfer table, no ack, nothing to expire. Every account already has a home, a file browser over it and a Files app on the phone, so a delivered file is an ordinary file from the moment it arrives. `Documents/SendOff/<machine>/` for something you sent yourself, and `Documents/SendOff/<sender>/` for another account's files. The home is the one that account actually browses — the owner's real login home, a member's managed home — because the two are different directories and writing to the wrong one makes a delivery invisible rather than wrong. CONSENT IS THE RECIPIENT'S, held as a row per pair. Not a role grant: a grant answers "may this role send files", and the person who should decide whether somebody may write into your home is you. Absence denies, and a sender who was not allowed does not see the recipient in their picker at all — the endpoint answers 404 for "no such account" and for "did not allow you" alike, so it cannot be used to enumerate accounts. The owner bypasses this as a SENDER only; receiving still needs their say-so. The sender's folder name comes from the token and never from the payload, so it cannot lie about who put a file there. Names are sanitised to one path segment and filenames to their basename — verified: `../../../../etc` becomes a literal folder, and a filename of `../../../../tmp/pwned.txt` writes `pwned.txt` inside the target. Collisions suffix ` (1)`; nothing is ever overwritten, because the sender cannot see the directory and would have no way to know. The push carries the folder name and a file count, and the catalogue renders "3 file(s) from andre" on the device. That relaxes "content does not travel" by a folder name and an integer — the owner's call, on the grounds that the file never leaves the tailnet and a notification nobody can act on is not worth sending. A filename would be content; whose folder it is, is addressing. `kind: 'app'` rather than `confined` even though it writes into a home: the path is one fixed shape chosen by the server from the caller's token, so there is nothing to traverse and nothing to read back. Requiring a Linux user would mean an account without one could not be sent a file, which is most of the point. Backend and verified end to end. The web send form is next. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
60 lines
3.0 KiB
TypeScript
60 lines
3.0 KiB
TypeScript
// The package's public surface.
|
|
//
|
|
// One line per feature, and nothing else. What each feature exports is stated in its own index.ts,
|
|
// beside the schema and queries it exports — so adding a query function means editing one file in one
|
|
// directory, not that file plus a list three levels up that nobody remembers to update.
|
|
//
|
|
// This was 297 lines of hand-written named exports until 2026-08-13. Every symbol was listed here, twice
|
|
// for most features (values, then types, repeating the path), and `db` and `schema` sat at line 270 with
|
|
// three feature blocks appended after them.
|
|
//
|
|
// The surface is unchanged: the same names are exported, they are just declared next to what they
|
|
// describe. 107 files import from 'officerdb' and none of them notice.
|
|
//
|
|
// ── Core above, plugins below ──
|
|
//
|
|
// The split mirrors schema.ts, where the plugin TABLES are commented out so db:push does not create
|
|
// them. These lines are NOT commented, and the difference is worth stating: commenting them would break
|
|
// nothing at runtime — hono.ts no longer mounts a single plugin router, so none of this is ever
|
|
// reached — but `bunx tsgo` checks every file under src/ whether it runs or not, and the plugin
|
|
// sidecars still import these symbols. So they stay exported until each plugin is extracted, and the
|
|
// blank line below is the only thing marking the boundary.
|
|
|
|
// The connection, and drizzle-kit's view of the schema. See ./schema.ts for the core/plugin split.
|
|
export { db, waitForDatabase } from './db';
|
|
export * as schema from './schema';
|
|
|
|
// ── Core ─────────────────────────────────────────────────────────────────────────────────────────
|
|
|
|
export * from './agent-panels';
|
|
export * from './api-keys';
|
|
export * from './app-store';
|
|
export * from './plugins';
|
|
export * from './auth';
|
|
export * from './permissions';
|
|
export * from './chat-events';
|
|
export * from './chat-session-models';
|
|
export * from './chat-notification-prefs';
|
|
export * from './nudges';
|
|
export * from './ai-provider-usage';
|
|
export * from './anthropic-accounts';
|
|
export * from './theme-favorites';
|
|
export { forgetChatSessions, sessionKeyForTranscriptId } from './chat-session-cleanup';
|
|
export * from './sendoff';
|
|
export * from './command-hq';
|
|
export * from './dashboards';
|
|
export * from './integrations';
|
|
export * from './pipeline-jobs';
|
|
export * from './server';
|
|
export * from './service-connections';
|
|
export * from './user-data';
|
|
|
|
// ── Plugins — exported only so tsgo stays clean; nothing mounts them ──────────────────────────────
|
|
|
|
export * from './dav';
|
|
export * from './notify';
|
|
|
|
// `operations` is absent because it no longer exists: it held task_logs, and the Task Logs feature was
|
|
// deleted end to end on 2026-08-13 after `task-logger.ts` turned out to have no callers — a full read
|
|
// path over a table nothing could write to.
|