Support FEP-ef61 portable ActivityPub IRIs in vocab codecs#850
Conversation
✅ Deploy Preview for fedify-json-schema canceled.
|
|
@codex review |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds portable ChangesFEP-ef61 Portable ActivityPub IRI Support
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces support for FEP-ef61 portable ActivityPub IRIs (using ap: and ap+ef61: schemes) within the generated vocabulary codecs. It adds new utility functions (canParseIri, parseIri, and formatIri) to handle parsing and canonical serialization of these IRIs, updates the vocabulary generation tools to integrate these utilities, and includes comprehensive tests. The review feedback suggests refining the PORTABLE_IRI_PATTERN regular expression in the class generator to prefix it with a double quote, ensuring it only matches the start of JSON string values and avoiding false positives in text properties.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5c67df65fe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codecov Report❌ Patch coverage is
... and 1 file with indirect coverage changes 🚀 New features to boost your workflow:
|
Generated codecs now look for portable ActivityPub IRIs only in ID-valued JSON-LD positions before deciding whether to bypass the raw JSON-LD cache. This keeps ordinary text such as post content from causing cache misses and dropping extension properties on default serialization. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request adds support for FEP-ef61 portable ActivityPub IRIs in generated vocabulary codecs, allowing "ap:" and "ap+ef61:" schemes to be parsed, serialized, and validated. Feedback on the changes highlights a potential Denial of Service (DoS) vulnerability in the generated "hasPortableIri" recursive function, which traverses JSON-LD objects without a depth limit or skipping the "@context" property. It is recommended to implement a recursion depth limit and skip "@context" to prevent stack overflow errors.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6f9581bd2a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Portable IRI formatting now preserves pct-encoded DID authority boundaries, and generated cache detection now inspects expanded JSON-LD with bounded traversal. That keeps alias-expanded portable IRIs from being cached in their raw form while avoiding unnecessary context walks. fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for FEP-ef61 portable ActivityPub IRIs in the generated vocabulary codecs. It adds utility functions (canParseIri, parseIri, and formatIri) to handle ap: and ap+ef61: schemes with DID authorities, ensuring they are correctly parsed into URL objects and serialized back to canonical ap+ef61: formats. The code generator and runtime codecs have been updated to integrate these utilities, and comprehensive tests have been added. The feedback suggests minor code simplifications: optimizing parseAtUri to avoid redundant string searches and using optional chaining in canContainIriValue to improve readability.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/vocab-runtime/src/url.ts`:
- Around line 67-71: Route URL inputs through the same portable-authority
normalization used by parsePortableIri(). In normalizePortableUrl(), do not
reconstruct the URL directly from iri.host/pathname; instead apply the same
did:-only authority validation and encodeURIComponent re-encoding logic so URL
and string inputs behave identically. Preserve the existing ap:/ap+ef61:
protocol acceptance in normalizePortableUrl(), but ensure the returned URL uses
the same internal portable-authority form as the parser.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: f66ccc6c-1f52-48ea-ac0a-c389348f1a57
⛔ Files ignored due to path filters (3)
packages/vocab-tools/src/__snapshots__/class.test.ts.deno.snapis excluded by!**/*.snappackages/vocab-tools/src/__snapshots__/class.test.ts.node.snapis excluded by!**/*.snappackages/vocab-tools/src/__snapshots__/class.test.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (5)
packages/vocab-runtime/src/url.test.tspackages/vocab-runtime/src/url.tspackages/vocab-tools/src/class.tspackages/vocab-tools/src/codec.tspackages/vocab/src/vocab.test.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8108116bdd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Portable URL instances now use the same authority validation and encoding path as string inputs, so DID boundaries and DID-internal percent escapes round-trip consistently. Generated cache detection also treats fedify:url scalar values as IRI-bearing fields without disabling caching for plain text fields. fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
|
@codex review |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for FEP-ef61 portable ActivityPub IRIs in the generated vocabulary codecs, allowing both ap: and ap+ef61: schemes to be parsed as URL objects and serialized canonically. To support this, new utility functions canParseIri, parseIri, and formatIri were added to the runtime and integrated into the vocabulary generation tools. Feedback on the changes highlights a potential TypeError in formatIri when processing relative URI strings, as it attempts to instantiate a URL without a base URL; a fallback check is recommended to improve robustness.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4b6047f952
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Pathless portable ActivityPub IRIs are now rejected before URL normalization, matching FEP-ef61's required path component. Non-portable relative strings passed to formatIri now remain unchanged instead of raising from the fallback URL formatter. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Portable URL instances now use the same authority validation and encoding path as string inputs, so DID boundaries and DID-internal percent escapes round-trip consistently. Generated cache detection also treats fedify:url scalar values as IRI-bearing fields without disabling caching for plain text fields. fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Pathless portable ActivityPub IRIs are now rejected before URL normalization, matching FEP-ef61's required path component. Non-portable relative strings passed to formatIri now remain unchanged instead of raising from the fallback URL formatter. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Portable IRI authority validation now treats the DID scheme case-insensitively while preserving the authority spelling for round-tripping. This keeps raw and percent-encoded DID authorities on the same validation path. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Portable IRI detection now treats JSON-LD value, list, and set containers as identifier positions when their parent property can hold IRIs. When a source document already uses those positions, the cached clone is normalized instead of being discarded, so extension data stays available without leaking raw portable IRI spelling. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Inline JSON-LD contexts can alias a known IRI property, so raw cache checks need to treat those aliases as portable IRI positions. The cached clone can then keep extension fields while still formatting the portable IRI value before it is reused. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Compact IRI aliases in inline JSON-LD contexts need the same raw cache handling as full IRI aliases. Expanding local prefixes lets the cached clone preserve caller terms and extension fields while still formatting portable IRI values before reuse. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
JSON-LD extension terms typed as @id can carry portable IRI values even when the term is not generated as a Fedify vocabulary property. Treating those terms as portable IRI positions keeps the cached JSON-LD clone and normalizes the value before it is reused. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Remote JSON-LD contexts can mark compacted extension terms as IRI values even when the cached JSON-LD only carries a context URL. Load those contexts while deciding which cached fields need portable IRI formatting, so unknown extension fields stay cached without rewriting plain text that merely mentions an ap:// string. Also treat @type: @id term definitions as IRI-valued even when the term has no explicit @id mapping, matching JSON-LD term definition semantics. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Cached JSON-LD can hide portable IRIs behind a remote context on a nested extension object. Make the cache scan and normalization path loader-aware at every object boundary, so nested aliases are discovered without rewriting plain text fields. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Repeated remote contexts should still contribute aliases to each object that references them. Cache the loaded context body by URL instead of only remembering that the URL was seen, so sibling extension objects can reuse the same @id aliases without another fetch. This also keeps failed custom loaders from crashing the cache scan when they return a nullish remote document. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Portable IRI cache normalization should not reimplement JSON-LD context handling over compact input. Normalize the expanded values produced by the JSON-LD processor, then compact them with the input context when one was supplied, so extension data is kept without a parallel context resolver. fedify-dev#850 Assisted-by: Codex:gpt-5.5
Portable IRI cache normalization already visits every expanded JSON-LD value. Return whether that pass changed anything so callers can decide whether to compact the normalized values without first scanning the same object graph with a separate predicate. fedify-dev#850 Assisted-by: Codex:gpt-5.5
Portable ActivityPub IRIs require a DID authority with a method and method-specific identifier. The previous scheme-only check accepted partial authorities that could not be real DIDs. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Normalize portable IRIs with lazy cloning so unchanged JSON-LD subtrees are not copied or mutated. Cache normalization now runs on the expanded input shape before parser-side mutations, which preserves contextless expanded arrays and their sibling graph nodes. fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Avoid overlapping DID method-specific-id matches by keeping colons as segment separators. Normalize portable string bases before resolving relative IRIs so decoded portable bases behave like parsed portable URLs. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
When portable IRI normalization requires expand and compact, carry back original top-level terms that JSON-LD expansion intentionally ignores. This keeps cache-only extension data round-tripping while still allowing context-aware portable IRI normalization. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
When compacted cache data already represents an original JSON-LD term through a canonical alias, do not copy the original alias back as an unmapped extension field. This keeps portable IRI normalization from leaving duplicate alias keys in the cached document. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Validate portable IRI authorities again after decoding encoded colons and percent signs. This keeps encoded DID authorities from accepting invalid percent escapes that the decoded spelling would reject. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Batch unmapped JSON-LD term checks into a single expansion so portable IRI cache merging does not expand each original key separately. Also await the merge before assigning the cached JSON-LD value so merge failures stay inside the cache fallback path. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Reject DID authorities whose literal DID path would expose malformed percent escapes after decoding an encoded percent sign. Also avoid mutating compacted JSON-LD objects while preserving unmapped terms, and clone normalized expanded cache data before subtype decoding mutates the working values object. fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Normalize at:// string bases before resolving relative IRIs, so raw DID colons do not make standard URL construction reject a valid base. Also keep single-element compact JSON-LD array cache entries compact by reading the element-level context and wrapping the compacted cache back in an array. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Return the original JSON-LD subtree reference from generated portable IRI normalization when no values change, so the decoder can detect cache rewrites by reference instead of allocating wrapper objects at every recursive step. Also leave encoded at:// bases on the standard URL path during relative IRI resolution, avoiding double-encoding of already URL-safe DID authorities. fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Avoid wrapping normalized expanded JSON-LD arrays again when the original input was already a single expanded node. The cache now only re-wraps compact array input after context-based compaction, keeping expanded cache output stable. Also keep generated portable IRI key discovery robust for redundant property metadata and restore alphabetical runtime import order in the generated classes. fedify-dev#850 (comment) fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Keep generated portable IRI cache normalization from collapsing compact JSON-LD single-item arrays after context-based compaction. The cache now reapplies the original compact array shape to the compacted result, so toJsonLd() preserves caller-provided array structure while still rewriting portable IRI strings. fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Handle portable IRI cache compaction for multi-node compact JSON-LD arrays by reusing contexts found inside array items and reshaping @graph output back to the caller-provided array form. Also bound the recursive shape pass and skip @context traversal while keeping the lazy clone behavior for unchanged subtrees. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Keep portable IRI cache compaction best effort by leaving malformed portable-looking extension IRIs unchanged instead of letting cache normalization throw. Compact JSON-LD array cache entries item by item so later nodes can use their own extension contexts and preserve caller-provided aliases. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Portable ActivityPub IRIs use custom URL schemes, so URL.origin is "null" even when the DID authorities differ. Compare custom-scheme IRIs by protocol and authority before trusting embedded objects, and parse fetched document URLs through parseIri() so portable bases are normalized consistently. Also accept DID method names that start with digits, matching the DID Core method-name grammar. fedify-dev#850 (comment) fedify-dev#850 (comment) Assisted-by: Codex:gpt-5.5
Note that the readable ap://did:... authority form is not RFC 3986 compliant, and that Fedify currently accepts it by normalizing the DID authority into a percent-encoded URL authority internally. Assisted-by: Codex:gpt-5.5
65a50ed to
6809204
Compare
|
@sij411 Just rebased! |
Fixes #826.
Why this is shaped this way
Fedify vocabulary objects already use
URLas the internal representation for IRI-like fields. This PR keeps that contract instead of introducing a parallel portable IRI type. The awkward part of FEP-ef61 is that the readable form uses a decoded DID authority, such asap+ef61://did:key:.../actor, while the platformURLparser needs that authority to be URL-safe. The new runtime helpers in packages/vocab-runtime/src/url.ts make that boundary explicit: parse portable ActivityPub IRIs into normalURLobjects with encoded authorities, then format thoseURLobjects back to canonicalap+ef61:strings when JSON-LD is emitted.That keeps the generated vocabulary classes from having to know the details of portable IRI parsing. packages/vocab-tools/src/codec.ts and packages/vocab-tools/src/type.ts now call the shared helpers wherever generated code previously reached for
new URL(),URL.canParse(), or.hrefon an IRI field. This also preserves the existingat://workaround in one place instead of duplicating it in the generated code.The JSON-LD cache path needed a small extra guard. When an object is built from JSON-LD that already contains portable IRIs, returning the raw cached document would skip the formatter and leak the input spelling back out. Generated codecs now only reuse the raw JSON-LD cache when the input does not contain
ap:orap+ef61:portable IRI syntax.Scope
This PR handles parsing and formatting for generated vocab codecs. It accepts
ap:andap+ef61:values with decoded or percent-encoded DID authorities, stores them internally as URL-safeURLobjects, and emits canonicalap+ef61:values with decoded DID authorities.It intentionally does not add comparison canonicalization that ignores query components. That belongs to the follow-up comparison work tracked separately in #828.
Verification
I covered the behavior at both levels: focused tests for the runtime helpers in packages/vocab-runtime/src/url.test.ts, and generated vocab behavior in packages/vocab/src/vocab.test.ts. The vocab test exercises object IDs, link-like properties, collection page links, decoded DID authorities, percent-encoded DID authorities, uppercase schemes, query strings, and JSON-LD round-tripping through
toJsonLd().I also regenerated the vocab-tools snapshots and updated the manual and changelog.
Commands run: