fedipod-server 0.13.0 → 0.13.1
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.
- package/lib/core/as2.mjs +9 -4
- package/lib/core/graphview.mjs +28 -8
- package/lib/gateway/front-core.mjs +14 -6
- package/package.json +1 -1
- package/web/app/agent.mjs +5 -2
- package/web/app/deliver-relay.mjs +18 -1
- package/web/app/dist/sw.js +32 -13
- package/web/app/dist/sw.js.map +3 -3
- package/web/app/site/sw.js +112 -27
package/web/app/site/sw.js
CHANGED
|
@@ -55555,10 +55555,16 @@ function indexQuads(quads) {
|
|
|
55555
55555
|
}
|
|
55556
55556
|
return { bySubject, objects, blanks };
|
|
55557
55557
|
}
|
|
55558
|
-
function findRoot({ bySubject, objects }) {
|
|
55559
|
-
|
|
55560
|
-
|
|
55561
|
-
|
|
55558
|
+
function findRoot({ bySubject, objects, blanks }) {
|
|
55559
|
+
const all = [...bySubject.keys()];
|
|
55560
|
+
const named = all.filter((s) => !blanks.has(s));
|
|
55561
|
+
const free = all.filter((s) => !objects.has(s));
|
|
55562
|
+
const freeNamed = free.find((s) => !blanks.has(s));
|
|
55563
|
+
if (freeNamed) return freeNamed;
|
|
55564
|
+
if (free.length) return free[0];
|
|
55565
|
+
for (const s of named) if (bySubject.get(s).has(RDF_TYPE)) return s;
|
|
55566
|
+
for (const s of all) if (bySubject.get(s).has(RDF_TYPE)) return s;
|
|
55567
|
+
return named[0] ?? all[0] ?? null;
|
|
55562
55568
|
}
|
|
55563
55569
|
function readList(head, ctx, depth, path) {
|
|
55564
55570
|
const out = [];
|
|
@@ -55636,7 +55642,7 @@ function makeView(subject, ctx, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
|
55636
55642
|
function graphView(quads, { root = null } = {}) {
|
|
55637
55643
|
if (!quads || !quads.length) return null;
|
|
55638
55644
|
const ctx = indexQuads(quads);
|
|
55639
|
-
const subject = root
|
|
55645
|
+
const subject = root && ctx.bySubject.has(root) ? root : findRoot(ctx);
|
|
55640
55646
|
if (!subject) return null;
|
|
55641
55647
|
const view = makeView(subject, ctx);
|
|
55642
55648
|
return view && typeof view === "object" ? view : null;
|
|
@@ -55695,19 +55701,21 @@ function groundContext(input) {
|
|
|
55695
55701
|
return { ...input, "@context": kept.length === 1 ? kept[0] : kept };
|
|
55696
55702
|
}
|
|
55697
55703
|
async function readLenient(raw) {
|
|
55704
|
+
let input = null;
|
|
55705
|
+
try {
|
|
55706
|
+
input = typeof raw === "string" ? JSON.parse(raw) : raw ?? null;
|
|
55707
|
+
} catch {
|
|
55708
|
+
}
|
|
55709
|
+
const own = input && typeof input === "object" ? input.id ?? input["@id"] : null;
|
|
55710
|
+
const root = typeof own === "string" && /^https?:\/\//u.test(own) ? own : null;
|
|
55698
55711
|
try {
|
|
55699
55712
|
const { doc, graph: graph2 } = await parseAS2(raw);
|
|
55700
|
-
return { doc, graph: graph2, view: graphView(graph2), degraded: null };
|
|
55713
|
+
return { doc, graph: graph2, view: graphView(graph2, { root }), degraded: null };
|
|
55701
55714
|
} catch (e) {
|
|
55702
|
-
let input = null;
|
|
55703
|
-
try {
|
|
55704
|
-
input = typeof raw === "string" ? JSON.parse(raw) : raw ?? null;
|
|
55705
|
-
} catch {
|
|
55706
|
-
}
|
|
55707
55715
|
if (!input || typeof input !== "object") return { doc: null, graph: null, view: null, degraded: e.message };
|
|
55708
55716
|
try {
|
|
55709
55717
|
const { graph: graph2 } = await parseAS2(groundContext(input));
|
|
55710
|
-
return { doc: input, graph: graph2, view: graphView(graph2), degraded: e.message };
|
|
55718
|
+
return { doc: input, graph: graph2, view: graphView(graph2, { root }), degraded: e.message };
|
|
55711
55719
|
} catch (inner) {
|
|
55712
55720
|
return { doc: input, graph: null, view: null, degraded: `${e.message}; grounded read also failed: ${inner.message}` };
|
|
55713
55721
|
}
|
|
@@ -57431,9 +57439,9 @@ async function onUpdate(intake, activity, actor) {
|
|
|
57431
57439
|
const note = await intake.fetchAP(objectId);
|
|
57432
57440
|
if (!note) throw new Error(`cannot refetch ${objectId} \u2014 will retry`);
|
|
57433
57441
|
if (note.id !== objectId || !isContentType(note.type)) return `object not verifiable content (${objectId}, ${note.type})`;
|
|
57434
|
-
const { attachmentsOf:
|
|
57442
|
+
const { attachmentsOf: attachmentsOf3, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
|
|
57435
57443
|
const content = titledContent2(note);
|
|
57436
|
-
const attachments =
|
|
57444
|
+
const attachments = attachmentsOf3(note);
|
|
57437
57445
|
const freshPoll = pollOf(note);
|
|
57438
57446
|
const freshEmojis = emojisOf(note);
|
|
57439
57447
|
intake.store.updateStatus(objectId, {
|
|
@@ -57567,8 +57575,8 @@ async function ingestNote(intake, objectId, actor, { via } = {}) {
|
|
|
57567
57575
|
const note = await intake.fetchAP(objectId);
|
|
57568
57576
|
if (!note) return `object fetch failed (${objectId})`;
|
|
57569
57577
|
if (note.id !== objectId || !isContentType(note.type)) return `object not verifiable content (${objectId}, ${note.type})`;
|
|
57570
|
-
const { attachmentsOf:
|
|
57571
|
-
const attachments =
|
|
57578
|
+
const { attachmentsOf: attachmentsOf3, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
|
|
57579
|
+
const attachments = attachmentsOf3(note);
|
|
57572
57580
|
const content = titledContent2(note);
|
|
57573
57581
|
const author = authorOf(note, actor);
|
|
57574
57582
|
if (!author) return `object names an author its origin does not vouch for (${objectId})`;
|
|
@@ -64488,6 +64496,16 @@ var postUrl = (uri) => {
|
|
|
64488
64496
|
const m = String(uri).match(/^at:\/\/([^/]+)\/[^/]+\/(.+)$/);
|
|
64489
64497
|
return m ? `https://bsky.app/profile/${m[1]}/post/${m[2]}` : null;
|
|
64490
64498
|
};
|
|
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
|
+
}
|
|
64491
64509
|
var BskyFeed = class {
|
|
64492
64510
|
constructor({ store, atproto, log: log2 = console.log, onNotification = null }) {
|
|
64493
64511
|
Object.assign(this, { store, atproto, log: log2, onNotification });
|
|
@@ -64543,14 +64561,27 @@ var BskyFeed = class {
|
|
|
64543
64561
|
return url;
|
|
64544
64562
|
}
|
|
64545
64563
|
// 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.
|
|
64546
64567
|
_mirrorPost(post, { via = null } = {}) {
|
|
64547
64568
|
const noteId = post.uri;
|
|
64548
|
-
const
|
|
64549
|
-
|
|
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
|
+
}
|
|
64550
64582
|
const actor = this._rememberAuthor(post.author);
|
|
64551
64583
|
if (this.store.isBlocked(actor)) return { noteId, added: false };
|
|
64552
64584
|
const text = post.record?.text || "";
|
|
64553
|
-
const images = post.embed?.images || [];
|
|
64554
64585
|
this.store.addStatus({
|
|
64555
64586
|
noteId,
|
|
64556
64587
|
actor,
|
|
@@ -64560,12 +64591,46 @@ var BskyFeed = class {
|
|
|
64560
64591
|
...post.cid ? { cid: post.cid } : {},
|
|
64561
64592
|
link: postUrl(noteId),
|
|
64562
64593
|
...via ? { via } : {},
|
|
64563
|
-
...
|
|
64564
|
-
|
|
64565
|
-
} : {}
|
|
64594
|
+
...inReplyTo ? { inReplyTo } : {},
|
|
64595
|
+
...attachments.length ? { attachments } : {}
|
|
64566
64596
|
});
|
|
64567
64597
|
return { noteId, added: true };
|
|
64568
64598
|
}
|
|
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
|
+
}
|
|
64569
64634
|
async sweep() {
|
|
64570
64635
|
if (!this.atproto?.connected()) return;
|
|
64571
64636
|
if (this.quietUntil && Date.now() < this.quietUntil) return;
|
|
@@ -64604,8 +64669,13 @@ var BskyFeed = class {
|
|
|
64604
64669
|
this.store.addNotification({ type: "follow", actor, bsky: true });
|
|
64605
64670
|
await this.onNotification?.(n, { actor });
|
|
64606
64671
|
} else if (n.reason === "mention" || n.reason === "reply") {
|
|
64607
|
-
|
|
64608
|
-
|
|
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 });
|
|
64609
64679
|
this.store.addNotification({ type: "mention", actor, noteId: n.uri, bsky: true });
|
|
64610
64680
|
await this.onNotification?.(n, { actor });
|
|
64611
64681
|
}
|
|
@@ -65937,6 +66007,10 @@ async function handle6(api, ctx) {
|
|
|
65937
66007
|
const mContext = /^\/api\/v1\/statuses\/([a-f0-9]+)\/context$/.exec(pathname);
|
|
65938
66008
|
if (mContext) {
|
|
65939
66009
|
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
|
+
}
|
|
65940
66014
|
const all = api.store.getStatuses();
|
|
65941
66015
|
const byId = new Map(all.map((s) => [s.noteId, s]));
|
|
65942
66016
|
const ancestors = [];
|
|
@@ -66372,8 +66446,8 @@ var TagFeed = class {
|
|
|
66372
66446
|
await this.intake.fetchAP(author).catch(() => {
|
|
66373
66447
|
});
|
|
66374
66448
|
}
|
|
66375
|
-
const { attachmentsOf:
|
|
66376
|
-
const attachments =
|
|
66449
|
+
const { attachmentsOf: attachmentsOf3, titledContent: titledContent2 } = await Promise.resolve().then(() => (init_wire(), wire_exports));
|
|
66450
|
+
const attachments = attachmentsOf3(note);
|
|
66377
66451
|
this.store.addStatus({
|
|
66378
66452
|
noteId,
|
|
66379
66453
|
actor: author,
|
|
@@ -67364,6 +67438,14 @@ var Deliverer = class {
|
|
|
67364
67438
|
|
|
67365
67439
|
// web/app/deliver-relay.mjs
|
|
67366
67440
|
init_fedify_sig();
|
|
67441
|
+
function doorKeyOf(doorInboxUrl) {
|
|
67442
|
+
try {
|
|
67443
|
+
const seg2 = new URL(doorInboxUrl).pathname.split("/");
|
|
67444
|
+
return seg2[1] === "u" && seg2[2] ? decodeURIComponent(seg2[2]) : null;
|
|
67445
|
+
} catch {
|
|
67446
|
+
return null;
|
|
67447
|
+
}
|
|
67448
|
+
}
|
|
67367
67449
|
var RelayDeliverer = class extends Deliverer {
|
|
67368
67450
|
constructor(opts) {
|
|
67369
67451
|
super(opts);
|
|
@@ -67388,6 +67470,7 @@ var RelayDeliverer = class extends Deliverer {
|
|
|
67388
67470
|
headers: {
|
|
67389
67471
|
date: s.headers.date,
|
|
67390
67472
|
digest: s.headers.digest,
|
|
67473
|
+
accept: s.headers.accept,
|
|
67391
67474
|
"content-type": s.headers["content-type"],
|
|
67392
67475
|
signature: s.headers.signature
|
|
67393
67476
|
}
|
|
@@ -69615,7 +69698,9 @@ var BrowserAgent = class _BrowserAgent {
|
|
|
69615
69698
|
actorId: this.urls.actor,
|
|
69616
69699
|
log: this.log,
|
|
69617
69700
|
relayUrl: `${frontOrigin.replace(/\/$/, "")}/api/relay`,
|
|
69618
|
-
|
|
69701
|
+
// The relay finds the account by the front's own key for it, which for a
|
|
69702
|
+
// mail-door account is the full address, not the bare handle.
|
|
69703
|
+
handle: doorKeyOf(config.gateway?.url) || config.handle,
|
|
69619
69704
|
sessionFetch: session.fetch
|
|
69620
69705
|
});
|
|
69621
69706
|
this.publisher = new Publisher({
|