style(13-03): apply Prettier formatting across repo

Mechanical reformat — no logic changes. 398 files changed, 19125
insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc
(singleQuote:true, semi:true, tabWidth:2, trailingComma:all,
printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
Lucas Berger
2026-06-11 20:35:18 -04:00
parent 4bc0445173
commit 982438dc10
398 changed files with 19050 additions and 16382 deletions
+37 -38
View File
@@ -17,11 +17,11 @@
* - coalesceListPush handles burst collapsing; this module owns audience + copy.
*/
import { eq, inArray } from 'drizzle-orm'
import { db } from '../db/client.js'
import { users, lists, listShares, pushSubscriptions } from '../db/schema.js'
import { coalesceListPush } from './pushCoalescer.js'
import { dispatchPush } from './pushDispatcher.js'
import { eq, inArray } from 'drizzle-orm';
import { db } from '../db/client.js';
import { users, lists, listShares, pushSubscriptions } from '../db/schema.js';
import { coalesceListPush } from './pushCoalescer.js';
import { dispatchPush } from './pushDispatcher.js';
/**
* Notify all accessible, non-actor subscribers that a list changed.
@@ -36,83 +36,82 @@ import { dispatchPush } from './pushDispatcher.js'
* for fast fake-timer or real-timer test execution.
*/
export function notifyListChange(listId: number, actorId: number, windowMs?: number): void {
coalesceListPush(listId, actorId, async (coalListId, coalActorId, count) => {
try {
await sendListChangePush(coalListId, coalActorId, count)
} catch (err: unknown) {
console.error(
`[listChangeDispatcher] unhandled error for list ${coalListId}:`,
err instanceof Error ? err.message : String(err),
)
}
}, windowMs)
coalesceListPush(
listId,
actorId,
async (coalListId, coalActorId, count) => {
try {
await sendListChangePush(coalListId, coalActorId, count);
} catch (err: unknown) {
console.error(
`[listChangeDispatcher] unhandled error for list ${coalListId}:`,
err instanceof Error ? err.message : String(err),
);
}
},
windowMs,
);
}
/**
* Inner dispatch: resolves actor name + list name, builds the audience,
* and sends a push to every accessible non-actor subscriber.
*/
async function sendListChangePush(
listId: number,
actorId: number,
count: number,
): Promise<void> {
async function sendListChangePush(listId: number, actorId: number, count: number): Promise<void> {
// Resolve actor display name and list name in parallel
const [actorRow, listRow] = await Promise.all([
db.select({ displayName: users.displayName }).from(users).where(eq(users.id, actorId)).limit(1),
db.select({ name: lists.name }).from(lists).where(eq(lists.id, listId)).limit(1),
])
]);
if (!listRow[0]) {
// List deleted between mutation and coalesce fire — no-op
return
return;
}
const actorName: string = actorRow[0]?.displayName ?? 'Someone'
const listName: string = listRow[0].name
const actorName: string = actorRow[0]?.displayName ?? 'Someone';
const listName: string = listRow[0].name;
// Build audience: list owner list_shares members, MINUS the actor (D-03)
const [ownerRows, shareRows] = await Promise.all([
db.select({ ownerId: lists.ownerId }).from(lists).where(eq(lists.id, listId)).limit(1),
db.select({ userId: listShares.userId }).from(listShares).where(eq(listShares.listId, listId)),
])
]);
if (!ownerRows[0]) {
// List gone — no-op
return
return;
}
const ownerId = ownerRows[0].ownerId
const shareUserIds = shareRows.map((r) => r.userId)
const ownerId = ownerRows[0].ownerId;
const shareUserIds = shareRows.map((r) => r.userId);
// Union of owner + sharees; deduplicate; exclude actor (D-03)
const audienceIds = [
...new Set([ownerId, ...shareUserIds]),
].filter((uid) => uid !== actorId)
const audienceIds = [...new Set([ownerId, ...shareUserIds])].filter((uid) => uid !== actorId);
if (audienceIds.length === 0) {
return
return;
}
// Load push subscriptions for all audience members
const subs = await db
.select()
.from(pushSubscriptions)
.where(inArray(pushSubscriptions.userId, audienceIds))
.where(inArray(pushSubscriptions.userId, audienceIds));
if (subs.length === 0) {
return
return;
}
// D-02 generic copy: "{Actor} made {N} changes to {ListName}"
// No item text — keeps the lock screen clean.
const body = `${actorName} made ${count} ${count === 1 ? 'change' : 'changes'} to ${listName}`
const body = `${actorName} made ${count} ${count === 1 ? 'change' : 'changes'} to ${listName}`;
const notification = {
title: listName,
body,
tag: `list-change:${listId}`,
navigate: `/lists/${listId}`,
}
};
// Fan out to each subscription; one failure must not abort the rest (T-05-04)
for (const sub of subs) {
@@ -120,7 +119,7 @@ async function sendListChangePush(
console.error(
`[listChangeDispatcher] dispatchPush failed for sub ${sub.id}:`,
err instanceof Error ? err.message : String(err),
)
})
);
});
}
}