grain.social is a photo sharing platform built on atproto.
1import { lexicons } from "$lexicon/lexicons.ts";
2import { bff, oauth, route } from "@bigmoves/bff";
3import { middlewares as xrpcApi } from "./api/mod.ts";
4import { Root } from "./app.tsx";
5import { LoginPage } from "./components/LoginPage.tsx";
6import { PDS_HOST_URL } from "./env.ts";
7import { onError } from "./lib/errors.ts";
8import { middlewares as comments } from "./modules/comments.tsx";
9import * as actions from "./routes/actions.tsx";
10import { handler as communityGuidelinesHandler } from "./routes/community_guidelines.tsx";
11import * as dialogs from "./routes/dialogs.tsx";
12import { handler as exploreHandler } from "./routes/explore.tsx";
13import { handler as followersHandler } from "./routes/followers.tsx";
14import { handler as followsHandler } from "./routes/follows.tsx";
15import { handler as galleryHandler } from "./routes/gallery.tsx";
16import { handler as hashtagHandler } from "./routes/hashtag.tsx";
17import * as legal from "./routes/legal.tsx";
18import { handler as notificationsHandler } from "./routes/notifications.tsx";
19import { handler as onboardHandler } from "./routes/onboard.tsx";
20import { handler as profileHandler } from "./routes/profile.tsx";
21import { handler as recordHandler } from "./routes/record.ts";
22import { handler as robotsHandler } from "./routes/robots.tsx";
23import { handler as supportHandler } from "./routes/support.tsx";
24import { handler as timelineHandler } from "./routes/timeline.tsx";
25import { handler as uploadHandler } from "./routes/upload.tsx";
26import { appStateMiddleware } from "./state.ts";
27import { onSignedIn } from "./utils.ts";
28
29bff({
30 appName: "Grain Social",
31 appLabelers: ["did:plc:nd45zozo34cr4pvxqu4rtr7e"],
32 appLabelerCollection: "social.grain.labeler.service",
33 collections: [
34 "social.grain.actor.profile",
35 "social.grain.gallery",
36 "social.grain.gallery.item",
37 "social.grain.photo",
38 "social.grain.photo.exif",
39 "social.grain.favorite",
40 "social.grain.graph.follow",
41 "social.grain.comment",
42 ],
43 externalCollections: [
44 "app.bsky.actor.profile",
45 "app.bsky.graph.follow",
46 "sh.tangled.actor.profile",
47 "sh.tangled.graph.follow",
48 ],
49 collectionKeyMap: {
50 "social.grain.favorite": ["subject"],
51 "social.grain.graph.follow": ["subject"],
52 "social.grain.gallery.item": ["gallery", "item"],
53 "social.grain.photo.exif": ["photo"],
54 "social.grain.comment": ["subject"],
55 },
56 // Used to exchange jwt token with mobile app
57 tokenCallbackUrl: "grainflutter://auth/callback",
58 lexicons,
59 rootElement: Root,
60 onError,
61 middlewares: [
62 ...xrpcApi,
63 appStateMiddleware,
64 oauth({
65 onSignedIn,
66 LoginComponent: LoginPage,
67 createAccountPdsHost: PDS_HOST_URL,
68 }),
69 route("/", timelineHandler),
70 route("/explore", exploreHandler),
71 route("/notifications", notificationsHandler),
72 route("/profile/:handleOrDid", profileHandler),
73 route("/profile/:handle/followers", followersHandler),
74 route("/profile/:handle/follows", followsHandler),
75 route("/profile/:handle/gallery/:rkey", galleryHandler),
76 route("/hashtag/:tag", hashtagHandler),
77 route("/upload", uploadHandler),
78 route("/onboard", onboardHandler),
79 route("/support", supportHandler),
80 route("/support/privacy", legal.privacyHandler),
81 route("/support/terms", legal.termsHandler),
82 route("/support/copyright", legal.copyrightHandler),
83 route("/support/community-guidelines", communityGuidelinesHandler),
84 route("/dialogs/create-account", dialogs.createAccount),
85 route("/dialogs/gallery/new", dialogs.createGallery),
86 route("/dialogs/gallery/:rkey", dialogs.editGallery),
87 route("/dialogs/gallery/:rkey/photos", dialogs.galleryPhotoSelect),
88 route("/dialogs/gallery/:rkey/edit", dialogs.editGalleryDetails),
89 route("/dialogs/gallery/:rkey/sort", dialogs.sortGallery),
90 route("/dialogs/gallery/:rkey/library", dialogs.galleryAddFromLibrary),
91 route("/dialogs/:creatorDid/gallery/:rkey/share", dialogs.galleryShare),
92 route("/dialogs/gallery/:did/select", dialogs.gallerySelect),
93 route("/dialogs/label/:src/:val", dialogs.labelValueDefinition),
94 route("/dialogs/profile", dialogs.editProfile),
95 route("/dialogs/avatar/:handle", dialogs.avatar),
96 route("/dialogs/image", dialogs.image),
97 route("/dialogs/photo/:rkey/remove", dialogs.photoRemove),
98 route("/dialogs/photo/:rkey/alt", dialogs.photoAlt),
99 route("/dialogs/photo/:rkey/exif", dialogs.photoExif),
100 route("/dialogs/photo/:did/:rkey/exif-overlay", dialogs.photoExifOverlay),
101 route("/dialogs/exif-info", dialogs.exifInfo),
102 route("/actions/update-seen", ["POST"], actions.updateSeen),
103 route("/actions/follow/:followeeDid", ["POST"], actions.follow),
104 route("/actions/follow/:followeeDid/:rkey", ["DELETE"], actions.unfollow),
105 route("/actions/create-edit", ["POST"], actions.galleryCreateEdit),
106 route("/actions/gallery/delete", ["POST"], actions.galleryDelete),
107 route(
108 "/actions/gallery/:rkey/add-photos",
109 ["PUT"],
110 actions.galleryAddPhotos,
111 ),
112 route(
113 "/actions/gallery/:galleryRkey/add-photo/:photoRkey",
114 ["PUT"],
115 actions.galleryAddPhoto,
116 ),
117 route(
118 "/actions/gallery/:galleryRkey/remove-photo/:photoRkey",
119 ["PUT"],
120 actions.galleryRemovePhoto,
121 ),
122 route("/actions/photo/:rkey", ["PUT"], actions.photoEdit),
123 route("/actions/photo/:rkey", ["DELETE"], actions.photoDelete),
124 route("/actions/photo", ["POST"], actions.uploadPhoto),
125 route(
126 "/actions/:creatorDid/gallery/:rkey/favorite",
127 ["POST"],
128 actions.galleryFavorite,
129 ),
130 route(
131 "/actions/:creatorDid/gallery/:rkey/favorite/:favRkey",
132 ["DELETE"],
133 actions.galleryUnfavorite,
134 ),
135 route("/actions/profile", ["PUT"], actions.profileUpdate),
136 route("/actions/gallery/:rkey/sort", ["POST"], actions.gallerySort),
137 route("/actions/get-blob", ["GET"], actions.getBlob),
138 ...comments,
139 route("/:did/:collection/:rkey", recordHandler),
140 route("/robots.txt", robotsHandler),
141 ],
142});