Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "edge-book",
"version": "0.18.2",
"version": "0.18.3",
"description": "Run your own Edge Book agent and connect it to the hosted reader.",
"license": "MIT",
"type": "module",
Expand Down
21 changes: 21 additions & 0 deletions src/store-notify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,27 @@ const NOTIFY_POLICIES: Partial<Record<MessageEnvelope["type"], NotifyPolicy>> =
dedup_key: env.message_id,
};
},
post_publish: async (env, store) => {
// Posts (signal/query/answer/endorse/coordinate/…) wrap the payload in
// body.post. Without a policy here these arrive silently — a friend's
// message would leave no notification at all. Surface a short preview.
const post = (env.body as { post?: { post_type?: unknown; body?: unknown; text?: unknown } }).post;
if (!post) return null;
const name = (await peerName(store, env.from_agent_id)) || env.from_agent_id;
const postType = typeof post.post_type === "string" ? post.post_type : "post";
const raw =
typeof post.body === "string" ? post.body :
typeof post.text === "string" ? post.text :
post.body != null ? JSON.stringify(post.body) : "";
Comment on lines +72 to +75

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include endorsement statements in post previews

For delivered endorse posts, the current post schema stores the human-readable content in statement, not body or text; this policy therefore falls through to an empty preview and emits only "<name> sent a endorse." for every endorsement notification. Since endorsements are one of the post types this change is intended to surface, hosts relying on the notify hook still won't see the actual endorsement content unless this also checks post.statement.

Useful? React with 👍 / 👎.

const preview = raw.length > 280 ? `${raw.slice(0, 279)}…` : raw;
return {
kind: "post_publish",
from_id: env.from_agent_id,
from_name: await peerName(store, env.from_agent_id),
message: preview ? `${name} (${postType}): ${preview}` : `${name} sent a ${postType}.`,
dedup_key: env.message_id,
};
},
object_share: async (env, store) => {
const body = env.body as unknown as ObjectShareBody;
const name = (await peerName(store, env.from_agent_id)) || env.from_agent_id;
Expand Down
26 changes: 26 additions & 0 deletions test/inbound-notify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,29 @@ test("unregistered/silent type (profile_share) yields a null intent", async () =
const env = envelopeOf("profile_share", aliceId, bobId, {}, "msg_ps_1");
assert.equal(await bob.notificationIntent(env), null);
});

test("notificationIntent renders a post_publish (coordinate) with a body preview", async () => {
// Regression: posts (signal/query/answer/coordinate/…) had no policy and
// arrived silently — a friend's message left no notification at all.
const { alice, bob } = await pair();
const aliceId = (await alice.identity()).agent_id;
const bobId = (await bob.identity()).agent_id;
const bobCard = await bob.writeCard();
// Seed Bob's contact for Alice so the renderer resolves her display_name.
await bob.receiveFriendRequest(await alice.createFriendRequest(bobCard));

const env = envelopeOf(
"post_publish", aliceId, bobId,
{ post: { post_type: "coordinate", body: "Hey Kublai — glad to connect." } },
"msg_pp_1",
);
const intent = await bob.notificationIntent(env);

assert.ok(intent, "post_publish should notify (was silent before)");
assert.equal(intent!.kind, "post_publish");
assert.equal(intent!.from_id, aliceId);
assert.match(intent!.message, /coordinate/, "names the post type");
assert.match(intent!.message, /glad to connect/, "includes a body preview");
assert.match(intent!.message, /Alice Agent/, "resolves sender name from contacts");
assert.equal(intent!.dedup_key, env.message_id);
});
Loading