Skip to content

"feat: integrate @solid/object and @volunteeringdata/object libraries#10

Merged
PreciousOritsedere merged 8 commits into
mainfrom
integrate-object-library
May 29, 2026
Merged

"feat: integrate @solid/object and @volunteeringdata/object libraries#10
PreciousOritsedere merged 8 commits into
mainfrom
integrate-object-library

Conversation

@PreciousOritsedere

Copy link
Copy Markdown
Collaborator
  • 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"
@vercel

vercel Bot commented May 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
profile-manager-demo Ready Ready Preview, Comment May 29, 2026 11:25am

Comment thread app/lib/class/Agent.ts Outdated
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).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See solid/object#30 instead.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://www.npmjs.com/package/@solid/object/v/0.6.0

I have implemented this, please see 0ead6f2

Comment thread app/lib/class/Agent.ts Outdated
get email(): string | null {
return this.hasEmail?.actualValue ?? null;
const emailNode = this.singularNullable(VCARD.hasEmail, TermAs.instance(VCardValueNode));
if (!emailNode) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a good readon to return null? Otherwise let them all be undefined if they are optional.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@langsamu The base Agent class in the published @solid/object@0.5.0 defines email and phone as string | null, so the override has to return null to match. Once #30 is released to npm, I'll remove these overrides completely and just use the library's email/phone directly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread app/lib/class/Agent.ts Outdated
Comment on lines +146 to +102
return (addr != null && addr !== "") ? addr : null;
return addr != null && addr !== "" ? addr : null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change does not belong in this PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — reverted the formatting change. See the commit here

Comment thread app/lib/class/Agent.ts Outdated
Comment on lines +1 to +11
/**
* 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.
*/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all comments that hinder readability and maintainability by redundantly explaining what the code does instead of why it does it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed. However, I only kept the comment explaining why VCardValueNode exists since that's not obvious from the code alone. See the commit

Comment thread app/lib/class/Agent.ts Outdated
Comment on lines +1 to +10
/**
* 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.
*/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all documentation comments that are actually explanatory comments.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. See the commit

Comment thread app/lib/helpers/profileUtils.ts Outdated
* 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use JSDoc constructs like @throws where appropriate.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please see the commit.

Comment thread app/lib/hooks/useAgent.ts Outdated
queryFn: () => fetchAndParseProfile(webId!, fetchFn),
enabled: !!webId,
gcTime: Number.POSITIVE_INFINITY,
// The Agent object uses lazy getters that read from an RDF store on access.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what? It's in-memory.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread app/lib/hooks/useAgent.ts Outdated
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like what?

Comment thread app/lib/hooks/useAgent.ts
// 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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this good practice?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, structuralSharing is a documented React Query option for exactly this case (class instances with getters/non-serializable data).

Comment on lines +78 to +92
/**
* 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;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well known antipattern. Please handle the exceptional case properly or model in a different way.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated safeGet to only catch TypeError. Please see the commit

- Revert cosmetic formatting change

@langsamu langsamu left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@PreciousOritsedere

Copy link
Copy Markdown
Collaborator Author

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

@PreciousOritsedere PreciousOritsedere merged commit dd54a86 into main May 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants