Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
56 linesCodeBlameRaw
1/**
2 * Clearing a person's conversation with @g1t (docs.g1t.sh/guides/ask/,
3 * "Clear the conversation"): everything said in their direct message with
4 * g1t is deleted for good, so g1t remembers none of it and the history is
5 * gone from Ask and from Chat.
6 *
7 * "New conversation" only leaves a mark (src/g1t.ts `conversation`); this
8 * deletes. What goes, from chat's own database: every message in the
9 * direct message (top-level and thread replies, g1t's answers with their
10 * steps and sources, the pages questions were asked from, marks, and the
11 * empty rows deleted messages left), their reactions, and the read mark
12 * and last activity that pointed at them. The direct message itself and
13 * its two members stay, empty, so the Ask panel and Chat open it as
14 * before. `chat_meter` stays: it counts messages and bytes per workspace
15 * per day for billing, with no text and no person in it.
16 *
17 * The rest of a clear is the service's (src/index.ts `g1tClear`): the
18 * channel's room throws away an answer still being written
19 * (src/room.ts `clear`), and notify forgets the person's notifications
20 * from it.
21 *
22 * Who may clear is decided here too, purely, so it is tested on its own
23 * (clear.test.ts): only the one person in a direct message with g1t, in
24 * their own.
25 */
26import { g1tDmPerson } from "./g1t.ts";
27
28/**
29 * Whether `viewer` (a member key, `user:<id>`) may clear this
30 * conversation: it is a direct message of exactly them and g1t. Never a
31 * channel, a group message, or anyone else's direct message with g1t,
32 * whatever their role.
33 */
34export function mayClear(input: { channelKind: "channel" | "dm"; members: readonly string[]; viewer: string }): boolean {
35 return input.channelKind === "dm" && g1tDmPerson(input.members) === input.viewer;
36}
37
38/** The part of D1 a clear uses. */
39type Db = Pick<D1Database, "prepare" | "batch">;
40
41/**
42 * Deletes everything said in one conversation, in one transaction (a D1
43 * batch), and says how many messages went. Clearing again finds nothing
44 * and deletes nothing: 0. The caller checks it is the viewer's own
45 * direct message with g1t ([`mayClear`]); this touches only `channelId`.
46 */
47export async function clearConversation(db: Db, channelId: string): Promise<{ messages: number }> {
48 const results = await db.batch([
49 db.prepare("DELETE FROM reactions WHERE message_id IN (SELECT id FROM messages WHERE channel_id = ?)").bind(channelId),
50 db.prepare("DELETE FROM messages WHERE channel_id = ?").bind(channelId),
51 // Nothing is left to have read, or to have been said last.
52 db.prepare("UPDATE channel_members SET last_read_id = NULL WHERE channel_id = ?").bind(channelId),
53 db.prepare("UPDATE channels SET last_message_at = NULL WHERE id = ?").bind(channelId),
54 ]);
55 return { messages: Number(results[1]?.meta?.changes ?? 0) };
56}