my monorepo for atproto based applications
1import path from "node:path";
2import dotenv from "dotenv";
3import { AtpAgent, BlobRef, AppBskyFeedDefs } from "@atproto/api";
4import fs from "fs/promises";
5import { ids } from "@my/lexicon/server/lexicons";
6
7const myFeeds = [
8 {
9 recordName: "heb-ppl",
10 displayName: "דוברי עברית",
11 description: 'פוסטים שנכתבו ע"י דוברי עברית',
12 avatar: path.join(__dirname, "avatars", "hep-ppl.png"),
13 },
14 {
15 recordName: "heb-ppl-all",
16 displayName: "דוברי עברית + תגובות",
17 description: 'פוסטים ותגובות שנכתבו ע"י דוברי עברית',
18 avatar: path.join(__dirname, "avatars", "hep-ppl-all.png"),
19 },
20];
21
22const descSuffix = [
23 "",
24 "הקוד של הפיד נמצא ב",
25 "https://tangled.sh/@drornir.dev/atprotocol-apps",
26].join("\n");
27
28const run = async () => {
29 dotenv.config();
30
31 const conf = {
32 handle: "@drornir.dev",
33 password: process.env.BLUESKY_PASSWORD,
34 service: "https://bsky.social",
35 };
36 if (!conf.password) {
37 throw new Error("Please provide a password in BLUESKY_PASSWORD");
38 }
39
40 if (!process.env.FEEDGEN_SERVICE_DID && !process.env.FEEDGEN_HOSTNAME) {
41 throw new Error("Please provide a hostname FEEDGEN_HOSTNAME");
42 }
43
44 const feedGenDid = process.env.FEEDGEN_SERVICE_DID ?? `did:web:${process.env.FEEDGEN_HOSTNAME}`;
45
46 // only update this if in a test environment
47 const agent = new AtpAgent({
48 service: conf.service,
49 });
50 await agent.login({ identifier: conf.handle, password: conf.password });
51
52 for (const feed of myFeeds) {
53 let avatarRef: BlobRef | undefined;
54 if (feed.avatar) {
55 let encoding: string;
56 if (feed.avatar.endsWith("png")) {
57 encoding = "image/png";
58 } else if (feed.avatar.endsWith("jpg") || feed.avatar.endsWith("jpeg")) {
59 encoding = "image/jpeg";
60 } else {
61 throw new Error("expected png or jpeg");
62 }
63 const img = await fs.readFile(feed.avatar);
64 const blobRes = await agent.com.atproto.repo.uploadBlob(img, {
65 encoding,
66 });
67 avatarRef = blobRes.data.blob;
68 }
69
70 console.log(`Publishing feed ${feed.recordName}...`);
71
72 await agent.com.atproto.repo.putRecord({
73 repo: agent.session?.did ?? "",
74 collection: ids.AppBskyFeedGenerator,
75 rkey: feed.recordName,
76 validate: true,
77 record: {
78 did: feedGenDid,
79 displayName: feed.displayName,
80 description: feed.description + descSuffix,
81 avatar: avatarRef,
82 createdAt: new Date().toISOString(),
83 contentMode: AppBskyFeedDefs.CONTENTMODEUNSPECIFIED,
84 },
85 });
86 }
87 console.log("All done 🎉");
88};
89
90run();