A TypeScript toolkit for consuming the Bluesky network in real-time.
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 252 lines 7.0 kB view raw
1import { z } from "zod"; 2 3// --- Jetstream Event Schemas --- 4 5export const CommitOperationSchema = z.enum(["create", "update", "delete"]); 6 7const CommitBaseSchema = z.object({ 8 rev: z.string(), 9 operation: CommitOperationSchema, 10 collection: z.string(), 11 rkey: z.string(), 12}); 13 14export const CommitCreatePayloadSchema = CommitBaseSchema.extend({ 15 operation: z.literal("create"), 16 record: z.any(), 17 cid: z.string(), 18}); 19 20export const CommitUpdatePayloadSchema = CommitBaseSchema.extend({ 21 operation: z.literal("update"), 22 record: z.any(), 23 cid: z.string(), 24}); 25 26export const CommitDeletePayloadSchema = CommitBaseSchema.extend({ 27 operation: z.literal("delete"), 28}); 29 30export const CommitPayloadSchema = z.discriminatedUnion("operation", [ 31 CommitCreatePayloadSchema, 32 CommitUpdatePayloadSchema, 33 CommitDeletePayloadSchema, 34]); 35 36const JetstreamEventBaseSchema = z.object({ 37 did: z.string(), 38 time_us: z.number(), 39}); 40 41export const JetstreamCommitEventSchema = JetstreamEventBaseSchema.extend({ 42 kind: z.literal("commit"), 43 commit: CommitPayloadSchema, 44}); 45 46export const IdentityPayloadSchema = z.object({ 47 did: z.string(), 48 handle: z.string(), 49 seq: z.number(), 50 time: z.string(), 51}); 52 53export const JetstreamIdentityEventSchema = JetstreamEventBaseSchema.extend({ 54 kind: z.literal("identity"), 55 identity: IdentityPayloadSchema, 56}); 57 58export const AccountStatusSchema = z.enum([ 59 "active", 60 "deactivated", 61 "suspended", 62 "deleted", 63 "takendown", 64]); 65 66export const AccountPayloadSchema = z.object({ 67 active: z.boolean(), 68 did: z.string(), 69 seq: z.number(), 70 time: z.string(), 71 status: AccountStatusSchema.optional(), 72}); 73 74export const JetstreamAccountEventSchema = JetstreamEventBaseSchema.extend({ 75 kind: z.literal("account"), 76 account: AccountPayloadSchema, 77}); 78 79export const JetstreamEventSchema = z.discriminatedUnion("kind", [ 80 JetstreamCommitEventSchema, 81 JetstreamIdentityEventSchema, 82 JetstreamAccountEventSchema, 83]); 84 85// --- Inferred types --- 86 87export type CommitOperation = z.infer<typeof CommitOperationSchema>; 88export type CommitBase = z.infer<typeof CommitBaseSchema>; 89export type CommitCreatePayload = z.infer<typeof CommitCreatePayloadSchema>; 90export type CommitUpdatePayload = z.infer<typeof CommitUpdatePayloadSchema>; 91export type CommitDeletePayload = z.infer<typeof CommitDeletePayloadSchema>; 92export type CommitPayload = z.infer<typeof CommitPayloadSchema>; 93export type JetstreamEventBase = z.infer<typeof JetstreamEventBaseSchema>; 94export type JetstreamCommitEvent = z.infer<typeof JetstreamCommitEventSchema>; 95export type IdentityPayload = z.infer<typeof IdentityPayloadSchema>; 96export type JetstreamIdentityEvent = z.infer<typeof JetstreamIdentityEventSchema>; 97export type AccountStatus = z.infer<typeof AccountStatusSchema>; 98export type AccountPayload = z.infer<typeof AccountPayloadSchema>; 99export type JetstreamAccountEvent = z.infer<typeof JetstreamAccountEventSchema>; 100export type JetstreamEvent = z.infer<typeof JetstreamEventSchema>; 101 102// --- Post Record Schema --- 103 104export const PostRecordSchema = z.object({ 105 text: z.string().min(1), 106 langs: z.array(z.string()).optional().default([]), 107 createdAt: z.string(), 108 facets: z.array(z.any()).optional(), 109 embed: z.object({ $type: z.string() }).passthrough().optional(), 110}); 111 112export type PostRecord = z.infer<typeof PostRecordSchema>; 113 114// --- Post Types --- 115 116export const PostDataSchema = z.object({ 117 did: z.string(), 118 text: z.string(), 119 langs: z.array(z.string()), 120 links: z.array(z.string()), 121 mentionCount: z.number(), 122 embedType: z.string().nullable(), 123 createdAt: z.string(), 124 uri: z.string(), 125 rkey: z.string(), 126}); 127 128export type PostData = z.infer<typeof PostDataSchema>; 129 130export const PostUpdateDataSchema = PostDataSchema.extend({ 131 cid: z.string(), 132}); 133 134export type PostUpdateData = z.infer<typeof PostUpdateDataSchema>; 135 136export const PostDeleteDataSchema = z.object({ 137 did: z.string(), 138 collection: z.string(), 139 rkey: z.string(), 140 uri: z.string(), 141}); 142 143export type PostDeleteData = z.infer<typeof PostDeleteDataSchema>; 144 145export const KeywordPostSchema = PostDataSchema.extend({ 146 matchedKeywords: z.array(z.string()), 147}); 148 149export type KeywordPost = z.infer<typeof KeywordPostSchema>; 150 151// --- User Types --- 152 153export const UserSchema = z.object({ 154 displayName: z.string(), 155 handle: z.string(), 156}); 157 158export type User = z.infer<typeof UserSchema>; 159 160export type UserRegistry = ReadonlyMap<string, User>; 161 162export const UserPostSchema = PostDataSchema.extend({ 163 displayName: z.string(), 164 handle: z.string(), 165}); 166 167export type UserPost = z.infer<typeof UserPostSchema>; 168 169// --- Config --- 170 171export const JetstreamConfigSchema = z.object({ 172 endpoint: z.string().optional(), 173 wantedCollections: z.array(z.string()).readonly().optional(), 174 wantedDids: z.array(z.string()).readonly().optional(), 175 requireHello: z.boolean().optional(), 176 cursor: z.number().optional(), 177 compress: z.boolean().optional(), 178 maxMessageSizeBytes: z.number().optional(), 179}); 180 181export type JetstreamConfig = z.infer<typeof JetstreamConfigSchema>; 182 183// --- API Option Types --- 184 185export const SearchPostsOptionsSchema = z.object({ 186 sort: z.enum(["top", "latest"]).optional(), 187 since: z.string().optional(), 188 until: z.string().optional(), 189 mentions: z.string().optional(), 190 author: z.string().optional(), 191 lang: z.string().optional(), 192 domain: z.string().optional(), 193 url: z.string().optional(), 194 tag: z.array(z.string()).readonly().optional(), 195 limit: z.number().optional(), 196 cursor: z.string().optional(), 197}); 198 199export type SearchPostsOptions = z.infer<typeof SearchPostsOptionsSchema>; 200 201export const GetAuthorFeedOptionsSchema = z.object({ 202 filter: z.enum([ 203 "posts_with_replies", 204 "posts_no_replies", 205 "posts_with_media", 206 "posts_and_author_threads", 207 ]).optional(), 208 limit: z.number().optional(), 209 cursor: z.string().optional(), 210 includePins: z.boolean().optional(), 211}); 212 213export type GetAuthorFeedOptions = z.infer<typeof GetAuthorFeedOptionsSchema>; 214 215export const PaginationOptionsSchema = z.object({ 216 limit: z.number().optional(), 217 cursor: z.string().optional(), 218}); 219 220export type PaginationOptions = z.infer<typeof PaginationOptionsSchema>; 221 222// --- PostView Types (API response shapes) --- 223 224export const PostViewSchema = z.object({ 225 uri: z.string(), 226 author: z.object({ 227 did: z.string(), 228 handle: z.string(), 229 displayName: z.string().optional(), 230 }).passthrough(), 231 record: z.object({ 232 text: z.string(), 233 }).passthrough(), 234 likeCount: z.number().optional(), 235 repostCount: z.number().optional(), 236 replyCount: z.number().optional(), 237 quoteCount: z.number().optional(), 238}).passthrough(); 239 240export type PostView = z.infer<typeof PostViewSchema>; 241 242export const PostViewInfoSchema = z.object({ 243 text: z.string(), 244 displayName: z.string(), 245 handle: z.string(), 246 did: z.string(), 247 rkey: z.string(), 248 bskyUrl: z.string(), 249 uri: z.string(), 250}); 251 252export type PostViewInfo = z.infer<typeof PostViewInfoSchema>;