tangled
alpha
login
or
join now
grain.social
/
grain
38
fork
atom
grain.social is a photo sharing platform built on atproto.
38
fork
atom
overview
issues
2
pulls
pipelines
feat: add notifications xrpc endpoint
chadtmiller.com
8 months ago
68521d20
0875518a
+190
-1
6 changed files
expand all
collapse all
unified
split
__generated__
index.ts
lexicons.ts
types
social
grain
notification
getNotifications.ts
deno.json
lexicons
social
grain
notification
getNotifications.json
src
api
mod.ts
+22
__generated__/index.ts
···
9
9
type StreamAuthVerifier,
10
10
} from "npm:@atproto/xrpc-server"
11
11
import { schemas } from './lexicons.ts'
12
12
+
import * as SocialGrainNotificationGetNotifications from './types/social/grain/notification/getNotifications.ts'
12
13
import * as SocialGrainGalleryGetGalleryThread from './types/social/grain/gallery/getGalleryThread.ts'
13
14
import * as SocialGrainGalleryGetActorGalleries from './types/social/grain/gallery/getActorGalleries.ts'
14
15
import * as SocialGrainGalleryGetGallery from './types/social/grain/gallery/getGallery.ts'
···
184
185
185
186
export class SocialGrainNS {
186
187
_server: Server
188
188
+
notification: SocialGrainNotificationNS
187
189
gallery: SocialGrainGalleryNS
188
190
graph: SocialGrainGraphNS
189
191
labeler: SocialGrainLabelerNS
···
193
195
194
196
constructor(server: Server) {
195
197
this._server = server
198
198
+
this.notification = new SocialGrainNotificationNS(server)
196
199
this.gallery = new SocialGrainGalleryNS(server)
197
200
this.graph = new SocialGrainGraphNS(server)
198
201
this.labeler = new SocialGrainLabelerNS(server)
199
202
this.feed = new SocialGrainFeedNS(server)
200
203
this.actor = new SocialGrainActorNS(server)
201
204
this.photo = new SocialGrainPhotoNS(server)
205
205
+
}
206
206
+
}
207
207
+
208
208
+
export class SocialGrainNotificationNS {
209
209
+
_server: Server
210
210
+
211
211
+
constructor(server: Server) {
212
212
+
this._server = server
213
213
+
}
214
214
+
215
215
+
getNotifications<AV extends AuthVerifier>(
216
216
+
cfg: ConfigOf<
217
217
+
AV,
218
218
+
SocialGrainNotificationGetNotifications.Handler<ExtractAuth<AV>>,
219
219
+
SocialGrainNotificationGetNotifications.HandlerReqCtx<ExtractAuth<AV>>
220
220
+
>,
221
221
+
) {
222
222
+
const nsid = 'social.grain.notification.getNotifications' // @ts-ignore
223
223
+
return this._server.xrpc.method(nsid, cfg)
202
224
}
203
225
}
204
226
+50
__generated__/lexicons.ts
···
2473
2473
},
2474
2474
},
2475
2475
},
2476
2476
+
SocialGrainNotificationGetNotifications: {
2477
2477
+
lexicon: 1,
2478
2478
+
id: 'social.grain.notification.getNotifications',
2479
2479
+
defs: {
2480
2480
+
main: {
2481
2481
+
type: 'query',
2482
2482
+
description:
2483
2483
+
'Enumerate notifications for the requesting account. Requires auth.',
2484
2484
+
parameters: {
2485
2485
+
type: 'params',
2486
2486
+
properties: {
2487
2487
+
limit: {
2488
2488
+
type: 'integer',
2489
2489
+
minimum: 1,
2490
2490
+
maximum: 100,
2491
2491
+
default: 50,
2492
2492
+
},
2493
2493
+
cursor: {
2494
2494
+
type: 'string',
2495
2495
+
},
2496
2496
+
},
2497
2497
+
},
2498
2498
+
output: {
2499
2499
+
encoding: 'application/json',
2500
2500
+
schema: {
2501
2501
+
type: 'object',
2502
2502
+
required: ['notifications'],
2503
2503
+
properties: {
2504
2504
+
cursor: {
2505
2505
+
type: 'string',
2506
2506
+
},
2507
2507
+
notifications: {
2508
2508
+
type: 'array',
2509
2509
+
items: {
2510
2510
+
type: 'ref',
2511
2511
+
ref: 'lex:social.grain.notification.defs#notificationView',
2512
2512
+
},
2513
2513
+
},
2514
2514
+
seenAt: {
2515
2515
+
type: 'string',
2516
2516
+
format: 'datetime',
2517
2517
+
},
2518
2518
+
},
2519
2519
+
},
2520
2520
+
},
2521
2521
+
},
2522
2522
+
},
2523
2523
+
},
2476
2524
SocialGrainCommentDefs: {
2477
2525
lexicon: 1,
2478
2526
id: 'social.grain.comment.defs',
···
3820
3868
ShTangledActorProfile: 'sh.tangled.actor.profile',
3821
3869
SocialGrainDefs: 'social.grain.defs',
3822
3870
SocialGrainNotificationDefs: 'social.grain.notification.defs',
3871
3871
+
SocialGrainNotificationGetNotifications:
3872
3872
+
'social.grain.notification.getNotifications',
3823
3873
SocialGrainCommentDefs: 'social.grain.comment.defs',
3824
3874
SocialGrainComment: 'social.grain.comment',
3825
3875
SocialGrainGalleryItem: 'social.grain.gallery.item',
+51
__generated__/types/social/grain/notification/getNotifications.ts
···
1
1
+
/**
2
2
+
* GENERATED CODE - DO NOT MODIFY
3
3
+
*/
4
4
+
import { HandlerAuth, HandlerPipeThrough } from "npm:@atproto/xrpc-server";
5
5
+
import express from "npm:express";
6
6
+
import { validate as _validate } from "../../../../lexicons.ts";
7
7
+
import { is$typed as _is$typed } from "../../../../util.ts";
8
8
+
import type * as SocialGrainNotificationDefs from "./defs.ts";
9
9
+
10
10
+
const is$typed = _is$typed,
11
11
+
validate = _validate;
12
12
+
const id = "social.grain.notification.getNotifications";
13
13
+
14
14
+
export interface QueryParams {
15
15
+
limit: number;
16
16
+
cursor?: string;
17
17
+
}
18
18
+
19
19
+
export type InputSchema = undefined;
20
20
+
21
21
+
export interface OutputSchema {
22
22
+
cursor?: string;
23
23
+
notifications: SocialGrainNotificationDefs.NotificationView[];
24
24
+
seenAt?: string;
25
25
+
}
26
26
+
27
27
+
export type HandlerInput = undefined;
28
28
+
29
29
+
export interface HandlerSuccess {
30
30
+
encoding: "application/json";
31
31
+
body: OutputSchema;
32
32
+
headers?: { [key: string]: string };
33
33
+
}
34
34
+
35
35
+
export interface HandlerError {
36
36
+
status: number;
37
37
+
message?: string;
38
38
+
}
39
39
+
40
40
+
export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough;
41
41
+
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
42
42
+
auth: HA;
43
43
+
params: QueryParams;
44
44
+
input: HandlerInput;
45
45
+
req: express.Request;
46
46
+
res: express.Response;
47
47
+
resetRouteRateLimits: () => Promise<void>;
48
48
+
};
49
49
+
export type Handler<HA extends HandlerAuth = never> = (
50
50
+
ctx: HandlerReqCtx<HA>,
51
51
+
) => Promise<HandlerOutput> | HandlerOutput;
+1
-1
deno.json
···
29
29
"dev:tailwind": "deno run -A --node-modules-dir npm:@tailwindcss/cli -i ./src/input.css -o ./build/styles.css --watch",
30
30
"dev:fonts": "rm -rf ./build/fonts && cp -r ./static/fonts/. ./build/fonts",
31
31
"sync": "deno run -A --env=.env jsr:@bigmoves/bff-cli@0.3.0-beta.40 sync --collections=social.grain.gallery,social.grain.actor.profile,social.grain.photo,social.grain.favorite,social.grain.gallery.item,social.grain.graph.follow,social.grain.photo.exif,social.grain.comment --external-collections=app.bsky.actor.profile,app.bsky.graph.follow,sh.tangled.graph.follow,sh.tangled.actor.profile --collection-key-map=\"{\\\"social.grain.favorite\\\":[\\\"subject\\\"],\\\"social.grain.graph.follow\\\":[\\\"subject\\\"],\\\"social.grain.gallery.item\\\":[\\\"gallery\\\",\\\"item\\\"],\\\"social.grain.photo.exif\\\":[\\\"photo\\\"],\\\"social.grain.comment\\\":[\\\"subject\\\"]}\"",
32
32
-
"codegen": "deno run -A jsr:@bigmoves/bff-cli@0.3.0-beta.40 lexgen"
32
32
+
"codegen": "deno run -A jsr:@bigmoves/bff-cli@0.3.0-beta.42 lexgen"
33
33
},
34
34
"compilerOptions": {
35
35
"jsx": "precompile",
+40
lexicons/social/grain/notification/getNotifications.json
···
1
1
+
{
2
2
+
"lexicon": 1,
3
3
+
"id": "social.grain.notification.getNotifications",
4
4
+
"defs": {
5
5
+
"main": {
6
6
+
"type": "query",
7
7
+
"description": "Enumerate notifications for the requesting account. Requires auth.",
8
8
+
"parameters": {
9
9
+
"type": "params",
10
10
+
"properties": {
11
11
+
"limit": {
12
12
+
"type": "integer",
13
13
+
"minimum": 1,
14
14
+
"maximum": 100,
15
15
+
"default": 50
16
16
+
},
17
17
+
"cursor": { "type": "string" }
18
18
+
}
19
19
+
},
20
20
+
"output": {
21
21
+
"encoding": "application/json",
22
22
+
"schema": {
23
23
+
"type": "object",
24
24
+
"required": ["notifications"],
25
25
+
"properties": {
26
26
+
"cursor": { "type": "string" },
27
27
+
"notifications": {
28
28
+
"type": "array",
29
29
+
"items": {
30
30
+
"type": "ref",
31
31
+
"ref": "social.grain.notification.defs#notificationView"
32
32
+
}
33
33
+
},
34
34
+
"seenAt": { "type": "string", "format": "datetime" }
35
35
+
}
36
36
+
}
37
37
+
}
38
38
+
}
39
39
+
}
40
40
+
}
+26
src/api/mod.ts
···
17
17
OutputSchema as GetGalleryThreadOutputSchema,
18
18
QueryParams as GetGalleryThreadQueryParams,
19
19
} from "$lexicon/types/social/grain/gallery/getGalleryThread.ts";
20
20
+
import {
21
21
+
OutputSchema as GetNotificationsOutputSchema,
22
22
+
} from "$lexicon/types/social/grain/notification/getNotifications.ts";
20
23
import { AtUri } from "@atproto/syntax";
21
24
import { BffMiddleware, OAUTH_ROUTES, route } from "@bigmoves/bff";
22
25
import { getActorGalleries, getActorProfileDetailed } from "../lib/actor.ts";
23
26
import { BadRequestError } from "../lib/errors.ts";
24
27
import { getGallery } from "../lib/gallery.ts";
28
28
+
import { getNotifications } from "../lib/notifications.ts";
25
29
import { getTimeline } from "../lib/timeline.ts";
26
30
import { getGalleryComments } from "../modules/comments.tsx";
27
31
···
100
104
{ feed: items.map((i) => i.gallery) } as GetTimelineOutputSchema,
101
105
);
102
106
}),
107
107
+
route(
108
108
+
"/xrpc/social.grain.notification.getNotifications",
109
109
+
(_req, _params, ctx) => {
110
110
+
// @TODO: this redirects, we should have a json response
111
111
+
ctx.requireAuth();
112
112
+
const notifications = getNotifications(
113
113
+
ctx,
114
114
+
);
115
115
+
return ctx.json(
116
116
+
{ notifications } as GetNotificationsOutputSchema,
117
117
+
);
118
118
+
},
119
119
+
),
103
120
];
104
121
105
122
function getProfileQueryParams(url: URL): GetProfileQueryParams {
···
130
147
if (!uri) throw new BadRequestError("Missing uri parameter");
131
148
return { uri };
132
149
}
150
150
+
151
151
+
// function getNotificationsQueryParams(url: URL): GetNotificationsQueryParams {
152
152
+
// const limit = parseInt(url.searchParams.get("limit") ?? "50", 10);
153
153
+
// if (isNaN(limit) || limit <= 0) {
154
154
+
// throw new BadRequestError("Invalid limit parameter");
155
155
+
// }
156
156
+
// const cursor = url.searchParams.get("cursor") ?? undefined;
157
157
+
// return { limit, cursor };
158
158
+
// }
133
159
134
160
// function getTimelineQueryParams(url: URL): GetTimelineQueryParams {
135
161
// const algorithm = url.searchParams.get("algorithm") ?? undefined;