Skip to content

Allow ActivityStreams Link objects in Object.icon and Object.image #790

@dahlia

Description

@dahlia

Since Fedify 0.4.0, Object's icon and image properties no longer accept Link objects. That was an intentional API simplification made around the same time singular accessors such as icon, image, getIcon(), and getImage() were added, but it means Fedify now rejects valid ActivityStreams 2.0 documents.

The ActivityStreams Vocabulary defines both icon and image with a range of Image | Link:

Fedify used to model those ranges that way. In 0.3.x, the vocabulary schema accepted both Image and Link for icon and image. The 0.4.0 changelog records the change explicitly:

  • Added singular accessors to Object's icon and image properties.
  • Object's icon and image properties no more accept Link objects.

That makes the TypeScript API easier to use when applications expect a resolved Image, but it also makes the JSON-LD parser reject explicit Link values that are valid ActivityStreams.

Affected versions

This appears to affect Fedify 0.4.0 and later, including the current main branch. It is not specific to a Deno, Node.js, Bun, or operating system version.

Steps to reproduce

import { Object } from "@fedify/vocab";

await Object.fromJsonLd({
  "@context": "https://www.w3.org/ns/activitystreams",
  id: "https://example.com/actor",
  type: "Object",
  icon: {
    type: "Link",
    href: "https://example.com/icon.png",
    mediaType: "image/png",
  },
});

The same problem applies to image:

import { Object } from "@fedify/vocab";

await Object.fromJsonLd({
  "@context": "https://www.w3.org/ns/activitystreams",
  id: "https://example.com/object",
  type: "Object",
  image: {
    type: "Link",
    href: "https://example.com/image.png",
    mediaType: "image/png",
  },
});

Expected behavior

Fedify should accept explicit ActivityStreams Link objects in icon and image, because they are allowed by the ActivityStreams 2.0 vocabulary.

Actual behavior

Fedify attempts to parse the value as an Image and throws:

TypeError: Invalid type: https://www.w3.org/ns/activitystreams#Link

This also breaks real-world ActivityPub objects. For example, https://tags.pub/user/activitypub currently uses:

{
  "icon": {
    "type": "Link",
    "href": "https://tags.pub/user/activitypub/icon"
  }
}

Related issue

This is related to #420, but it is not the same issue.

#420 is about bare URL strings in icon or image, such as:

{
  "icon": "https://example.com/icon.png"
}

That case is harder because the ActivityStreams JSON-LD context maps icon and image string values through @type: @id, so the parser sees an IRI reference. Deciding whether Fedify should treat that string as a dereferenceable Image, a Link.href, or an unresolved resource needs separate policy work.

This issue is narrower. It is only about explicit Link objects:

{
  "icon": {
    "type": "Link",
    "href": "https://example.com/icon.png"
  }
}

There is no ambiguity in that input. The publisher has already said that the value is a Link.

Suggested direction

Long term, Fedify should probably restore the vocabulary-level TypeScript types for icon and image to Image | Link, matching ActivityStreams 2.0. That would make constructors, clone(), getIcon(), getImage(), getIcons(), and getImages() reflect the real range of the vocabulary.

That change would widen public TypeScript return types and could break existing code that assumes getIcon() and getImage() only return Image. It should probably wait for the next major release, Fedify 3.0.

For the current major version, a smaller compatibility fix may be better:

  • Keep the public TypeScript API for icon and image as Image-oriented.
  • Accept explicit Link objects while parsing incoming JSON-LD.
  • Normalize those Link objects into the best available Image representation internally, for example by constructing an Image whose url is the link's href and whose mediaType, width, height, and related link metadata are preserved when possible.
  • Leave Fedify fails to handle URL strings for icon property #420 open for the separate bare URL string behavior.

The implementation mechanism for that short-term compatibility path is discussed in #792.

This would make Fedify accept valid ActivityStreams documents without forcing a TypeScript API widening before 3.0.

Metadata

Metadata

Assignees

No one assigned

    Type

    Priority

    Medium

    Effort

    High

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions