"feat: integrate @solid/object and @volunteeringdata/object libraries#10
Conversation
PreciousOritsedere
commented
May 19, 2026
- Replace custom Agent with extension of @solid/object's Agent
- Remove redundant vocabulary constants handled by the library
- Delete WebIdDataset (no longer needed)
- Simplify profileUtils to use Agent constructor directly
- Replace wrapVolunteerProfile with VolunteerProfile constructor
- Add VCardValueNode workaround for @solid/object HasValue infinite recursion bug
- Add safeGet wrapper for graceful handling of Pod data mismatches
- Add structuralSharing: false for React Query Agent caching"
- Replace custom Agent with extension of @solid/object's Agent - Remove redundant vocabulary constants handled by the library - Delete WebIdDataset (no longer needed) - Simplify profileUtils to use Agent constructor directly - Replace wrapVolunteerProfile with VolunteerProfile constructor - Add VCardValueNode workaround for @solid/object HasValue infinite recursion bug - Add safeGet wrapper for graceful handling of Pod data mismatches - Add structuralSharing: false for React Query Agent caching"
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| export class Agent extends BaseAgent { | ||
| /** | ||
| * Override email to avoid @solid/object's HasValue class which has a | ||
| * .value getter that conflicts with N3's termToId (causes infinite recursion). |
There was a problem hiding this comment.
See solid/object#30 instead.
Thanks for the fix in solid/object#30! The published npm version (0.5.0) still has the issue. Happy to remove it once a new release is published, could you cut a new release of the package with the fix please?
There was a problem hiding this comment.
There was a problem hiding this comment.
I have implemented this, please see 0ead6f2
| get email(): string | null { | ||
| return this.hasEmail?.actualValue ?? null; | ||
| const emailNode = this.singularNullable(VCARD.hasEmail, TermAs.instance(VCardValueNode)); | ||
| if (!emailNode) return null; |
There was a problem hiding this comment.
Is there a good readon to return null? Otherwise let them all be undefined if they are optional.
There was a problem hiding this comment.
There was a problem hiding this comment.
this is also done — upgraded to @solid/object@0.6.0. The email/phone overrides and VCardValueNode workaround are removed entirely. see the commit here
| return (addr != null && addr !== "") ? addr : null; | ||
| return addr != null && addr !== "" ? addr : null; |
There was a problem hiding this comment.
This change does not belong in this PR.
There was a problem hiding this comment.
Fixed — reverted the formatting change. See the commit here
| /** | ||
| * Extended Agent — adds project-specific properties on top of @solid/object's Agent. | ||
| * | ||
| * The base Agent from @solid/object already provides: | ||
| * vcardFn, foafName, name, email, hasEmail, phone, hasTelephone, | ||
| * organization, role, title, website, vcardHasUrl, foafHomepage, | ||
| * photoUrl, storageUrls, pimStorage, solidStorage, oidcIssuer, knows | ||
| * | ||
| * We extend only for properties not yet in the shared library. | ||
| */ | ||
|
|
There was a problem hiding this comment.
Please remove all comments that hinder readability and maintainability by redundantly explaining what the code does instead of why it does it.
There was a problem hiding this comment.
Removed. However, I only kept the comment explaining why VCardValueNode exists since that's not obvious from the code alone. See the commit
| /** | ||
| * Extended Agent — adds project-specific properties on top of @solid/object's Agent. | ||
| * | ||
| * The base Agent from @solid/object already provides: | ||
| * vcardFn, foafName, name, email, hasEmail, phone, hasTelephone, | ||
| * organization, role, title, website, vcardHasUrl, foafHomepage, | ||
| * photoUrl, storageUrls, pimStorage, solidStorage, oidcIssuer, knows | ||
| * | ||
| * We extend only for properties not yet in the shared library. | ||
| */ |
There was a problem hiding this comment.
Please remove all documentation comments that are actually explanatory comments.
| * Agent wrapping that WebID subject. | ||
| * | ||
| * Pure async — caching and dedup are handled by React Query (useAgent hook). | ||
| * Throws if the fetch or parse fails — the WebID is required for the app. |
There was a problem hiding this comment.
Please use JSDoc constructs like @throws where appropriate.
| queryFn: () => fetchAndParseProfile(webId!, fetchFn), | ||
| enabled: !!webId, | ||
| gcTime: Number.POSITIVE_INFINITY, | ||
| // The Agent object uses lazy getters that read from an RDF store on access. |
There was a problem hiding this comment.
I have improved the comment to explain the actual cause. It's the infinite recursion from the library's .value getter, not the in-memory store itself. See the commit
| gcTime: Number.POSITIVE_INFINITY, | ||
| // The Agent object uses lazy getters that read from an RDF store on access. | ||
| // React Query normally tries to compare old vs new data by walking every property, | ||
| // which would accidentally call those getters and cause errors. Turning this off |
| // React Query normally tries to compare old vs new data by walking every property, | ||
| // which would accidentally call those getters and cause errors. Turning this off | ||
| // tells React Query to just use the new Agent as-is without comparing it. | ||
| structuralSharing: false, |
There was a problem hiding this comment.
yes, structuralSharing is a documented React Query option for exactly this case (class instances with getters/non-serializable data).
| /** | ||
| * Safely access an agent property that may throw at runtime. | ||
| * Some Solid Pods store data in unexpected formats (e.g. a plain text literal | ||
| * where the library expects a URL/NamedNode). When that happens, @rdfjs/wrapper | ||
| * throws a type error. We catch it here and return null so that one bad field | ||
| * doesn't break the entire profile. | ||
| */ | ||
| function safeGet<T>(fn: () => T): T | null { | ||
| try { | ||
| return fn(); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Well known antipattern. Please handle the exceptional case properly or model in a different way.
There was a problem hiding this comment.
I updated safeGet to only catch TypeError. Please see the commit
- Revert cosmetic formatting change
langsamu
left a comment
There was a problem hiding this comment.
A lot has improved but there are still inconsistencies and antipatterns.
I don't want to hold you back but may I recommend following up on the remaining comments in a different change.
I have pushed some commits to address all the reviews you left |