home · login to get plonkin'

get deleted posts from Jetstream

@roland.cros.by · 9h ago · typescript · 155 loc · raw · 0 comments

1#!/usr/bin/env -S deno --allow-net --allow-env23import * as path from "jsr:@std/path";4import { simpleFetchHandler, XRPC } from "npm:@atcute/client";5import { JetstreamSubscription } from "npm:@atcute/jetstream";6import * as TID from "npm:@atcute/tid";78function usage() {9  const scriptName = path.basename(Deno.mainModule);10  console.log(11    `Usage:12  ${scriptName} at://handle-or-did/collection/rkey13  ${scriptName} https://bsky.app/profile/handle-or-did/post/rkey14  ${scriptName} handle-or-did rkey`,15  );16  Deno.exit(1);17}1819if (Deno.args.length < 1 || Deno.args.length > 2) {20  usage();21}2223const atRegex = /at:\/\/([^/]+)\/([^/]+)\/([^/"]+)/;2425let didOrHandle;26let did;27let collection;28let rkey;29if (Deno.args.length == 1) {30  if (Deno.args[0].startsWith("at://")) {31    const match = Deno.args[0].match(atRegex);32    if (match) {33      didOrHandle = match[1];34      collection = match[2];35      rkey = match[3];36    } else usage();37  } else {38    const match = Deno.args[0].match(/\/profile\/([^/]+)\/post\/([2-7a-z]+)/);39    if (match) {40      didOrHandle = match[1];41      collection = "app.bsky.feed.post";42      rkey = match[2];43    } else usage();44  }45} else {46  didOrHandle = Deno.args[0];47  rkey = Deno.args[1];48  collection = "app.bsky.feed.post";49}5051if (didOrHandle.startsWith("did:")) {52  did = didOrHandle;53} else {54  const handler = simpleFetchHandler({55    service: "https://public.api.bsky.app",56  });57  const rpc = new XRPC({ handler });58  try {59    const { data } = await rpc.get("com.atproto.identity.resolveHandle", {60      params: { handle: didOrHandle },61    });62    did = data.did;63  } catch (e) {64    console.error(e);65    Deno.exit(1);66  }67}6869console.log(did, rkey);7071function dateFromTID(tid: String): Date {72  return new Date(TID.parse(tid).timestamp / 1000.0);73}7475function dateFromCursor(cursor: Number): Date {76  return new Date(cursor / 1000.0);77}7879function formatDate(date: Date): string {80  return date.toISOString().replace("T", " ").replace("Z", "");81}8283function atURILink(did: string, collection: string, rkey: string): string {84  const atURI = `at://${did}/${collection}/${rkey}`;85  return `\x1b]8;;https://pdsls.dev/${atURI}\x1b\\${atURI}\x1b]8;;\x1b\\`;86}8788function linkify(text: string): string {89  return text.replace(90    /at:\/\/([^/]+)\/([^/]+)\/([^/"]+)/g,91    (match, did, collection, rkey) => {92      return atURILink(did, collection, rkey);93    },94  );95}9697async function getSingleEvent() {98  const subscription = new JetstreamSubscription({99    url: "wss://jetstream1.us-east.bsky.network",100  });101  for await (const event of subscription) {102    if (event.kind === "commit") return event;103  }104  throw new Error("No commit events received");105}106107// const event = await getSingleEvent();108// console.log(109//   `Latest:110// Cursor: ${formatDate(dateFromCursor(event.time_us))} (${event.time_us})111// Rev:    ${formatDate(dateFromTID(event.commit.rev))} (${event.commit.rev})`,112// );113114const postTime = dateFromTID(rkey);115const offset = 5 * 60 * 1000;116const startCursor = (postTime.getTime() - offset) * 1000;117118console.log(119  `Target:120Rkey time:    ${formatDate(postTime)} (${rkey})121Start cursor: ${formatDate(dateFromCursor(startCursor))} (${startCursor})122`,123);124125const subscription = new JetstreamSubscription({126  url: "wss://jetstream2.us-east.bsky.network",127  wantedCollections: [collection],128  wantedDids: [did],129  cursor: startCursor,130});131132for await (const event of subscription) {133  if (event.kind === "commit") {134    const atURI = atURILink(135      event.did,136      event.commit.collection,137      event.commit.rkey,138    );139    console.log(140      `Stream event ${atURI}141Rev time: ${formatDate(dateFromTID(event.commit.rev))} (${event.commit.rev})142Cursor:   ${formatDate(dateFromCursor(event.time_us))} (${event.time_us})143`,144    );145    if (event.commit.rkey === rkey) {146      console.log(`Found post ${atURI}`);147      console.log(linkify(JSON.stringify(event, null, 2)));148      break;149    } else if (event.commit.rkey > rkey) {150      console.log("Saw event with rkey after expected rkey");151      break;152    }153  }154}155

login to post a comment