Skip to content

Commit 5936534

Browse files
authored
Merge pull request #948 from Bananamilk452/issue-946-add-more-infos-in-pragmatics
Enhance pragmatics documentation with new sections and examples
2 parents b4ee305 + 22b03d3 commit 5936534

1 file changed

Lines changed: 176 additions & 0 deletions

File tree

‎docs/manual/pragmatics.md‎

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,37 @@ to these objects through their `tags` property. The exact way ActivityPub
434434
implementations render these objects differs, but Mastodon and Misskey already
435435
share a number of de facto conventions.
436436

437+
### `to`, `cc`
438+
439+
> [!NOTE]
440+
> You can find more information in the [Specifying an activity] document.
441+
442+
The objects described above can have `to` and `cc` properties that address
443+
their intended audience. These properties can also be used on other
444+
ActivityStreams objects, including activities.
445+
The `to` property identifies primary recipients, while `cc` identifies
446+
secondary recipients. To address multiple recipients, use the `tos` and `ccs`
447+
properties.
448+
449+
~~~~ typescript twoslash
450+
import { Note, PUBLIC_COLLECTION } from "@fedify/vocab";
451+
import { type Context } from "@fedify/fedify";
452+
const ctx = null as unknown as Context<void>;
453+
const identifier: string = "";
454+
// ---cut-before---
455+
new Note({
456+
to: PUBLIC_COLLECTION,
457+
cc: ctx.getFollowersUri(identifier),
458+
// additional things...
459+
});
460+
~~~~
461+
462+
This combination addresses the public collection as the primary audience and
463+
the actor's followers as the secondary audience. Mastodon uses this convention
464+
for public posts.
465+
466+
[Specifying an activity]: ./send.md#specifying-an-activity
467+
437468
### `Note`: Short posts
438469

439470
The `Note` type is the most common object type for short posts. In Mastodon,
@@ -729,3 +760,148 @@ For example, the above `Emoji` object is displayed like the following in
729760
Mastodon:
730761

731762
![Screenshot: A rendered custom emoji in Mastodon](pragmatics/mastodon-emoji.png)
763+
764+
### Replies
765+
766+
To reply to an object, create a `Note` whose `replyTarget` is the object being
767+
replied to, a `Link` to it, or its canonical URL. Fedify serializes
768+
`replyTarget` as the standard ActivityStreams `inReplyTo` property in JSON-LD.
769+
770+
For a public reply, address the public collection in `to`, and add the replying
771+
actor's followers and the parent object's author to `cc`. Also add a `Mention`
772+
tag for the parent author, with a matching mention link in `content`:
773+
774+
~~~~ typescript twoslash
775+
import type { Context } from "@fedify/fedify";
776+
import { Mention, Note, PUBLIC_COLLECTION } from "@fedify/vocab";
777+
const ctx = null as unknown as Context<void>;
778+
const identifier = "alice";
779+
const parentNote = new URL("https://example.net/notes/123");
780+
const parentAuthor = new URL("https://example.net/users/bob");
781+
// ---cut-before---
782+
new Note({
783+
content: // [!code highlight]
784+
'<p><a class="mention u-url" href="https://example.net/users/bob">' +
785+
"@bob@example.net</a> Thanks for sharing this!</p>",
786+
replyTarget: parentNote, // [!code highlight]
787+
to: PUBLIC_COLLECTION, // [!code highlight]
788+
ccs: [ // [!code highlight]
789+
ctx.getFollowersUri(identifier),
790+
parentAuthor,
791+
],
792+
tags: [ // [!code highlight]
793+
new Mention({
794+
href: parentAuthor,
795+
name: "@bob@example.net",
796+
}),
797+
],
798+
})
799+
~~~~
800+
801+
The `to` and `cc` values are audience addresses, not inbox URLs. In particular,
802+
use the parent author's actor URL in `cc`, then deliver the `Create` activity to
803+
that actor through `Context.sendActivity()`. Give the enclosing `Create`
804+
activity the same `to` and `cc` values as its `Note` object.
805+
806+
Mastodon uses the `inReplyTo` property to attach a reply to its parent thread.
807+
Addressing the parent author in `cc` delivers the reply to them, while a
808+
matching `Mention` tag creates a notification; neither establishes the thread
809+
relationship. Ensure the `Mention.href`, `Mention.name`, and the mention link
810+
in `content` all identify the same actor. For a non-public or direct reply, do
811+
not use `PUBLIC_COLLECTION` or the followers collection; address only the
812+
actors who should be able to see the conversation instead.
813+
814+
### Allowing quotes
815+
816+
[FEP-044f] defines consent-respecting quote posts. To allow anyone to quote a
817+
`Note` automatically, set its `interactionPolicy.canQuote.automaticApproval`
818+
property to `PUBLIC_COLLECTION`:
819+
820+
~~~~ typescript twoslash
821+
import { InteractionPolicy, InteractionRule, Note, PUBLIC_COLLECTION } from "@fedify/vocab";
822+
// ---cut-before---
823+
new Note({
824+
content: "<p>Anyone may quote this note.</p>",
825+
interactionPolicy: new InteractionPolicy({ // [!code highlight]
826+
canQuote: new InteractionRule({ // [!code highlight]
827+
automaticApproval: PUBLIC_COLLECTION, // [!code highlight]
828+
}),
829+
}),
830+
})
831+
~~~~
832+
833+
Advertising this policy improves interoperability with quote-aware
834+
implementations. Mastodon 4.4 verifies and displays remote FEP-044f quotes,
835+
and Mastodon 4.5 can author quotes and set automatic quote policies.
836+
[Hackers' Pub] and [Hollo] also support FEP-044f quote policies and the
837+
authorization flow.
838+
839+
> [!NOTE]
840+
> Misskey's `_misskey_quote` property is a non-standard extension that only
841+
> identifies the quoted object's URL. FEP-044f's `quote` property represents
842+
> the same relationship, but its `interactionPolicy.canQuote`, `QuoteRequest`,
843+
> and `QuoteAuthorization` terms also let implementations obtain, verify, and
844+
> revoke the original author's consent. Fedify's `Note.quoteUrl` supports the
845+
> legacy `_misskey_quote`, `quoteUrl`, and `quoteUri` properties for
846+
> compatibility, while `Note.getQuote()` and `Note.quoteId` represent FEP-044f's
847+
> `quote` property.
848+
849+
To require the author's approval instead, use `manualApproval` with the actors
850+
or collections that may request a quote. The policy advertises whether a quote
851+
is expected to be allowed, but it does not authorize a quote by itself. Under
852+
FEP-044f, the quoting actor sends a `QuoteRequest`; after accepting it, the
853+
original author returns an `Accept` activity whose `result` is a
854+
`QuoteAuthorization`. The quote post then references that authorization.
855+
856+
See the [interaction controls] documentation for the helpers that evaluate
857+
`canQuote` policies and create or verify quote authorizations.
858+
859+
[FEP-044f]: https://helge.codeberg.page/fep/fep/044f/
860+
[Hackers' Pub]: https://hackers.pub/
861+
[Hollo]: https://hollo.social/
862+
[interaction controls]: ./interaction-controls.md
863+
864+
### Microformats
865+
866+
[Microformats 2] is a convention for embedding machine-readable metadata in
867+
HTML with CSS class names. In federated posts, `Note.content` is HTML, so a
868+
receiving implementation cannot reliably infer whether an arbitrary link is an
869+
account mention, a hashtag, or an ordinary external link from its visible text
870+
alone. The classes provide that missing semantic information.
871+
872+
> [!TIP]
873+
> Microformats are not required by ActivityPub, so a post remains valid without
874+
> them. Nevertheless, adding them is recommended for interoperability with
875+
> Mastodon and other implementations that recognize these conventions.
876+
> See Mastodon's [Microformats specification] for the classes it supports.
877+
878+
For example, write a mention as an `h-card` containing a `u-url` link. The
879+
`h-card` identifies the linked text as a person or organization, and `u-url`
880+
identifies the link as that account's profile permalink. Mastodon also uses
881+
its `mention` class to open the link as an in-app account mention instead of a
882+
generic URL:
883+
884+
~~~~ html
885+
<p>Hello
886+
<span class="h-card">
887+
<a class="u-url mention" href="https://example.com/users/friend">
888+
<span class="p-name">@friend@example.com</span>
889+
</a>
890+
</span>!
891+
</p>
892+
~~~~
893+
894+
The `mention` class is a Mastodon-specific extension, not a Microformats class.
895+
Likewise, use `class="hashtag"` and `rel="tag"` on hashtag links so Mastodon
896+
can treat them as hashtags rather than ordinary links. These classes describe
897+
the HTML representation only; they do not replace ActivityPub metadata. Keep
898+
the corresponding `Mention` or `Hashtag` object in `Note.tags`, with the same
899+
URL and displayed name, so implementations can correctly process the post,
900+
including notifications and thread handling.
901+
902+
When generating `content`, preserve these classes through HTML sanitization.
903+
Removing them may leave the link clickable, but Mastodon-compatible clients can
904+
lose its mention or hashtag behavior.
905+
906+
[Microformats 2]: https://microformats.io/
907+
[Microformats specification]: https://docs.joinmastodon.org/spec/microformats/

0 commit comments

Comments
 (0)