"feat: integrate @solid/object and @volunteeringdata/object libraries#10
"feat: integrate @solid/object and @volunteeringdata/object libraries#10PreciousOritsedere wants to merge 1 commit into
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). |
| 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.
| 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.
| /** | ||
| * 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.
| /** | ||
| * 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. |
| 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, |
| /** | ||
| * 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.