1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
import { experimental_trpcMiddleware } from "@trpc/server";
import { z } from "zod";
import {
zBookmarkListSchema,
zEditBookmarkListSchemaWithValidation,
zNewBookmarkListSchema,
} from "@hoarder/shared/types/lists";
import type { AuthedContext } from "../index";
import { authedProcedure, router } from "../index";
import { List } from "../models/lists";
import { ensureBookmarkOwnership } from "./bookmarks";
export const ensureListOwnership = experimental_trpcMiddleware<{
ctx: AuthedContext;
input: { listId: string };
}>().create(async (opts) => {
const list = await List.fromId(opts.ctx, opts.input.listId);
return opts.next({
ctx: {
...opts.ctx,
list,
},
});
});
export const listsAppRouter = router({
create: authedProcedure
.input(zNewBookmarkListSchema)
.output(zBookmarkListSchema)
.mutation(async ({ input, ctx }) => {
return await List.create(ctx, input).then((l) => l.list);
}),
edit: authedProcedure
.input(zEditBookmarkListSchemaWithValidation)
.output(zBookmarkListSchema)
.use(ensureListOwnership)
.mutation(async ({ input, ctx }) => {
return await ctx.list.update(input);
}),
delete: authedProcedure
.input(
z.object({
listId: z.string(),
}),
)
.use(ensureListOwnership)
.mutation(async ({ ctx }) => {
await ctx.list.delete();
}),
addToList: authedProcedure
.input(
z.object({
listId: z.string(),
bookmarkId: z.string(),
}),
)
.use(ensureListOwnership)
.use(ensureBookmarkOwnership)
.mutation(async ({ input, ctx }) => {
await ctx.list.addBookmark(input.bookmarkId);
}),
removeFromList: authedProcedure
.input(
z.object({
listId: z.string(),
bookmarkId: z.string(),
}),
)
.use(ensureListOwnership)
.use(ensureBookmarkOwnership)
.mutation(async ({ input, ctx }) => {
await ctx.list.removeBookmark(input.bookmarkId);
}),
get: authedProcedure
.input(
z.object({
listId: z.string(),
}),
)
.output(zBookmarkListSchema)
.use(ensureListOwnership)
.query(({ ctx }) => {
return ctx.list.list;
}),
list: authedProcedure
.output(
z.object({
lists: z.array(zBookmarkListSchema),
}),
)
.query(async ({ ctx }) => {
const results = await List.getAll(ctx);
return { lists: results.map((l) => l.list) };
}),
getListsOfBookmark: authedProcedure
.input(z.object({ bookmarkId: z.string() }))
.output(
z.object({
lists: z.array(zBookmarkListSchema),
}),
)
.use(ensureBookmarkOwnership)
.query(async ({ input, ctx }) => {
const lists = await List.forBookmark(ctx, input.bookmarkId);
return { lists: lists.map((l) => l.list) };
}),
stats: authedProcedure
.output(
z.object({
stats: z.map(z.string(), z.number()),
}),
)
.query(async ({ ctx }) => {
const lists = await List.getAll(ctx);
const sizes = await Promise.all(lists.map((l) => l.getSize()));
return { stats: new Map(lists.map((l, i) => [l.list.id, sizes[i]])) };
}),
});
|