fedipod-server 0.13.1 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34555,8 +34555,40 @@ var PodStore = class {
34555
34555
  this.cache.set("ids.json", ids);
34556
34556
  return id;
34557
34557
  }
34558
+ // The map first, for ids minted under an older scheme. Then, because the
34559
+ // id IS the hash of the url, whatever this store knows is scanned for the
34560
+ // url that hashes to it — actors, posts, contacts, requests, media. The
34561
+ // browser build's worker is stopped whenever it idles, and the in-memory
34562
+ // map went with it: a client clicking an account it had just been shown
34563
+ // reached a fresh worker that held the actor and could not name it.
34558
34564
  urlFor(id) {
34559
- return this.getIds()[id] || null;
34565
+ const ids = this.getIds();
34566
+ if (ids[id]) return ids[id];
34567
+ if (!/^[a-f0-9]{16}$/u.test(String(id))) return null;
34568
+ const hash = (u) => node_crypto_default.createHash("sha256").update(u).digest("hex").slice(0, 16);
34569
+ const seen = /* @__PURE__ */ new Set();
34570
+ const candidates = function* (store) {
34571
+ for (const u of Object.keys(store.getActors())) yield u;
34572
+ for (const st2 of store.getStatuses()) {
34573
+ yield st2.noteId;
34574
+ yield st2.actor;
34575
+ for (const a of st2.attachments || []) if (a?.url) yield a.url;
34576
+ }
34577
+ const c = store.getContacts();
34578
+ for (const f of [...c.followers, ...c.following]) if (f?.actor) yield f.actor;
34579
+ for (const r of store.getRequests()) if (r?.actor) yield r.actor;
34580
+ for (const u of Object.keys(store.getMedia())) yield u;
34581
+ };
34582
+ for (const u of candidates(this)) {
34583
+ if (typeof u !== "string" || seen.has(u)) continue;
34584
+ seen.add(u);
34585
+ if (hash(u) === id) {
34586
+ ids[id] = u;
34587
+ this.cache.set("ids.json", ids);
34588
+ return u;
34589
+ }
34590
+ }
34591
+ return null;
34560
34592
  }
34561
34593
  };
34562
34594
 
@@ -57439,9 +57471,9 @@ async function onUpdate(intake, activity, actor) {
57439
57471
  const note = await intake.fetchAP(objectId);
57440
57472
  if (!note) throw new Error(`cannot refetch ${objectId} \u2014 will retry`);
57441
57473
  if (note.id !== objectId || !isContentType(note.type)) return `object not verifiable content (${objectId}, ${note.type})`;
57442
- const { attachmentsOf: attachmentsOf3, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
57474
+ const { attachmentsOf: attachmentsOf2, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
57443
57475
  const content = titledContent2(note);
57444
- const attachments = attachmentsOf3(note);
57476
+ const attachments = attachmentsOf2(note);
57445
57477
  const freshPoll = pollOf(note);
57446
57478
  const freshEmojis = emojisOf(note);
57447
57479
  intake.store.updateStatus(objectId, {
@@ -57575,8 +57607,8 @@ async function ingestNote(intake, objectId, actor, { via } = {}) {
57575
57607
  const note = await intake.fetchAP(objectId);
57576
57608
  if (!note) return `object fetch failed (${objectId})`;
57577
57609
  if (note.id !== objectId || !isContentType(note.type)) return `object not verifiable content (${objectId}, ${note.type})`;
57578
- const { attachmentsOf: attachmentsOf3, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
57579
- const attachments = attachmentsOf3(note);
57610
+ const { attachmentsOf: attachmentsOf2, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
57611
+ const attachments = attachmentsOf2(note);
57580
57612
  const content = titledContent2(note);
57581
57613
  const author = authorOf(note, actor);
57582
57614
  if (!author) return `object names an author its origin does not vouch for (${objectId})`;
@@ -64496,16 +64528,6 @@ var postUrl = (uri) => {
64496
64528
  const m = String(uri).match(/^at:\/\/([^/]+)\/[^/]+\/(.+)$/);
64497
64529
  return m ? `https://bsky.app/profile/${m[1]}/post/${m[2]}` : null;
64498
64530
  };
64499
- function attachmentsOf2(post) {
64500
- const e = post?.embed || {};
64501
- const images = [...e.images || [], ...e.media?.images || []].filter((i) => i?.fullsize).map((i) => ({ url: i.fullsize, mediaType: "image/jpeg", description: i.alt || "" }));
64502
- const card = e.external?.thumb || e.media?.external?.thumb;
64503
- if (card) {
64504
- const ext = e.external || e.media.external;
64505
- images.push({ url: card, mediaType: "image/jpeg", description: ext.title || ext.uri || "" });
64506
- }
64507
- return images;
64508
- }
64509
64531
  var BskyFeed = class {
64510
64532
  constructor({ store, atproto, log: log2 = console.log, onNotification = null }) {
64511
64533
  Object.assign(this, { store, atproto, log: log2, onNotification });
@@ -64561,27 +64583,14 @@ var BskyFeed = class {
64561
64583
  return url;
64562
64584
  }
64563
64585
  // One Bluesky post into the statuses index. Returns its noteId, new or not.
64564
- // A post seen before is completed, not duplicated: a reply first met as a
64565
- // bare notification record learns its parent and its pictures from the
64566
- // full view when that arrives.
64567
64586
  _mirrorPost(post, { via = null } = {}) {
64568
64587
  const noteId = post.uri;
64569
- const inReplyTo = post.record?.reply?.parent?.uri || null;
64570
- const attachments = attachmentsOf2(post);
64571
- const existing = this.store.getStatuses().find((s) => s.noteId === noteId);
64572
- if (existing) {
64573
- const patch = {
64574
- ...inReplyTo && !existing.inReplyTo ? { inReplyTo } : {},
64575
- ...attachments.length && !existing.attachments?.length ? { attachments } : {}
64576
- };
64577
- if (Object.keys(patch).length && typeof this.store.updateStatus === "function") {
64578
- this.store.updateStatus(noteId, patch);
64579
- }
64580
- return { noteId, added: false };
64581
- }
64588
+ const existing = this.store.getStatuses().some((s) => s.noteId === noteId);
64589
+ if (existing) return { noteId, added: false };
64582
64590
  const actor = this._rememberAuthor(post.author);
64583
64591
  if (this.store.isBlocked(actor)) return { noteId, added: false };
64584
64592
  const text = post.record?.text || "";
64593
+ const images = post.embed?.images || [];
64585
64594
  this.store.addStatus({
64586
64595
  noteId,
64587
64596
  actor,
@@ -64591,46 +64600,12 @@ var BskyFeed = class {
64591
64600
  ...post.cid ? { cid: post.cid } : {},
64592
64601
  link: postUrl(noteId),
64593
64602
  ...via ? { via } : {},
64594
- ...inReplyTo ? { inReplyTo } : {},
64595
- ...attachments.length ? { attachments } : {}
64603
+ ...images.length ? {
64604
+ attachments: images.map((i) => ({ url: i.fullsize, mediaType: "image/jpeg", description: i.alt || "" }))
64605
+ } : {}
64596
64606
  });
64597
64607
  return { noteId, added: true };
64598
64608
  }
64599
- // The conversation under one post, asked for when a post is opened: the
64600
- // ancestors it hangs from and the replies beneath it, each mirrored with
64601
- // the reply link the thread view is built from. View cache only, like the
64602
- // timeline. Returns how many posts were new; a thread Bluesky will not
64603
- // give (gone, blocked, rate-limited) adds none and is logged, not thrown.
64604
- async mirrorThread(uri, { depth = 6 } = {}) {
64605
- if (!this.atproto?.connected()) return 0;
64606
- if (this.quietUntil && Date.now() < this.quietUntil) return 0;
64607
- let out;
64608
- try {
64609
- out = await this.atproto.xrpc("app.bsky.feed.getPostThread", { params: { uri, depth, parentHeight: 40 } });
64610
- } catch (e) {
64611
- if (e.status === 429 || e.status >= 500) this._backOff(e.status, null);
64612
- else this.log(`bskyfeed: thread ${uri}: ${e.message}`);
64613
- return 0;
64614
- }
64615
- const self2 = this.atproto.read()?.did;
64616
- const ownMirrors = new Set(this.store.getStatuses().map((s) => s.atproto?.uri).filter(Boolean));
64617
- let added = 0;
64618
- const take2 = (node) => {
64619
- const post = node?.post;
64620
- if (!post?.uri) return;
64621
- if (post.author?.did === self2 && ownMirrors.has(post.uri)) return;
64622
- if (this._mirrorPost(post).added) added++;
64623
- };
64624
- for (let up = out?.thread?.parent; up; up = up.parent) take2(up);
64625
- const walk = (node, left) => {
64626
- take2(node);
64627
- if (left <= 0) return;
64628
- for (const r of node?.replies || []) walk(r, left - 1);
64629
- };
64630
- walk(out?.thread, depth);
64631
- if (added) this.log(`bskyfeed: +${added} from the thread under ${uri}`);
64632
- return added;
64633
- }
64634
64609
  async sweep() {
64635
64610
  if (!this.atproto?.connected()) return;
64636
64611
  if (this.quietUntil && Date.now() < this.quietUntil) return;
@@ -64669,13 +64644,8 @@ var BskyFeed = class {
64669
64644
  this.store.addNotification({ type: "follow", actor, bsky: true });
64670
64645
  await this.onNotification?.(n, { actor });
64671
64646
  } else if (n.reason === "mention" || n.reason === "reply") {
64672
- let view = null;
64673
- try {
64674
- const got = await this.atproto.xrpc("app.bsky.feed.getPosts", { params: { uris: n.uri } });
64675
- view = (got?.posts || [])[0] || null;
64676
- } catch {
64677
- }
64678
- this._mirrorPost(view || { uri: n.uri, cid: n.cid, author: n.author, record: n.record, indexedAt: n.indexedAt });
64647
+ const record = { uri: n.uri, cid: n.cid, author: n.author, record: n.record, indexedAt: n.indexedAt };
64648
+ this._mirrorPost(record);
64679
64649
  this.store.addNotification({ type: "mention", actor, noteId: n.uri, bsky: true });
64680
64650
  await this.onNotification?.(n, { actor });
64681
64651
  }
@@ -65493,7 +65463,8 @@ async function handle4(api, ctx) {
65493
65463
  }
65494
65464
  const hit = Object.entries(api.store.getActors()).find(([u, a]) => {
65495
65465
  try {
65496
- return `${a.preferredUsername}@${new URL(u).host}` === acct;
65466
+ const at = new URL(u);
65467
+ return `${a.preferredUsername}@${at.host}` === acct || `${a.preferredUsername}@${at.hostname}` === acct;
65497
65468
  } catch {
65498
65469
  return false;
65499
65470
  }
@@ -66007,10 +65978,6 @@ async function handle6(api, ctx) {
66007
65978
  const mContext = /^\/api\/v1\/statuses\/([a-f0-9]+)\/context$/.exec(pathname);
66008
65979
  if (mContext) {
66009
65980
  const noteUrl = api.lookup(mContext[1]).s?.noteId;
66010
- const opened = noteUrl && api.store.getStatuses().find((x) => x.noteId === noteUrl);
66011
- if (opened?.kind === "bsky" && typeof api.agent?.bskyfeed?.mirrorThread === "function") {
66012
- await api.agent.bskyfeed.mirrorThread(noteUrl);
66013
- }
66014
65981
  const all = api.store.getStatuses();
66015
65982
  const byId = new Map(all.map((s) => [s.noteId, s]));
66016
65983
  const ancestors = [];
@@ -66446,8 +66413,8 @@ var TagFeed = class {
66446
66413
  await this.intake.fetchAP(author).catch(() => {
66447
66414
  });
66448
66415
  }
66449
- const { attachmentsOf: attachmentsOf3, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
66450
- const attachments = attachmentsOf3(note);
66416
+ const { attachmentsOf: attachmentsOf2, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
66417
+ const attachments = attachmentsOf2(note);
66451
66418
  this.store.addStatus({
66452
66419
  noteId,
66453
66420
  actor: author,