Skip to content

feat(solid-memo-client): add a Solid client of the app's own - #332

Merged
ixuz merged 4 commits into
mainfrom
alt-solid-client
Oct 27, 2026
Merged

ixuz merged 4 commits into
mainfrom
alt-solid-client

Conversation

@ixuz

@ixuz ixuz commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

What and why

Solid Memo reads and writes pods, and signs in, through Inrupt's libraries alone. #323 put them behind modules of the app's own, but with no second implementation, nothing showed that those seams hold. This adds one, @solid-memo/solid-memo-client (packages/solid-memo-client), which uses no Inrupt package:

  • RDF data and resources on n3 and jsonld-streaming-parser, with plain fetch. It sends the same requests and PATCH bodies as Inrupt's client.
  • Solid-OIDC sign-in on oauth4webapi, with PKCE and DPoP-bound tokens from a WebCrypto key that can't be extracted. The key, the refresh token and the provider's registration are kept in IndexedDB, and access tokens in memory only. Refresh and logout take a Web Lock, so tabs don't race.
  • The public-read grant on WAC and ACP. It grants nothing beyond public read, never writes acl:default, and keeps the owner's control.
  • shacl's Turtle reader on n3.

Inrupt's clients stay the default. SOLID_CLIENT=solid-memo-client makes a build or a test run use the new client through a Vite plugin (scripts/solidClient.ts), which resolves each client module to its namesake in the new package, so no caller changes. Leaving it unset, or setting inrupt, keeps Inrupt; any other value fails when a config loads. Turbo hashes the choice, so a cached result never stands for the other client.

The commits:

  1. refactor(solid): client/sparqlUpdate.ts takes the changes it writes instead of importing them from the Inrupt RDF module. The PATCH bodies are unchanged.
  2. feat(solid-memo-client): the package, at 100% coverage, passing the same contract suites; the switch; boundary rules (no Inrupt import in it, and no package imports it); and check:exports and check:dependencies taught about it.
  3. ci: two advisory jobs with the switch on: solid-memo-client (unit) runs the solid, shacl, composition and web tests, and solid-memo-client (<server>) runs the pod tests on each blocking server. They show a failure without holding up a merge.
  4. docs: docs/solid-memo-client.md covers what it is built on, how it keeps a session, how it grants access, where it differs from Inrupt's client, and how it is tested. The vendor, boundary, sign-in, privacy, standards, testing and architecture pages say where it fits.

With the switch on, I also ran:

  • the pod tests on css-6, css-7, nss-5, nss-6 and css-acp, with the same counts as Inrupt's client on css-7;
  • the smoke, returning-learner, study-reload and studio journeys in Chromium against the Community Solid Server;
  • a build of the site, whose JavaScript holds no Inrupt code.

After merging: keep the two solid-memo-client jobs out of the required checks in the branch protection rules. They are advisory, and they add six jobs to each run.

Closes: #331

Checklist

  • One issue. This pull request addresses one issue, linked above.
  • One step. This pull request does not finish its issue, so it says Refs:, not Closes:. Leave this unchecked otherwise.
  • Done, as AGENTS.md defines it: npm run check passes (lint, Markdown and spelling included), npm run lint:reuse too if a file was added, and npm run crosscheck too if ns/ or decks/ changed. (npm run check passes on each commit; lint:reuse and lint:workflows pass too; crosscheck n/a: ns/ and decks/ are unchanged.)
  • Tests. New and changed code has its tests, and every package stays at 100% coverage (docs/testing.md).
  • Docs. The docs say what changed, and a new page in docs/ is listed in docs/docs.ttl.
  • Languages. A new or changed message is in every locale: en, sv, ko, de, es and fr (packages/ui/src/i18n/). (n/a: no message changed)
  • Vocabulary and shapes. Any change to ns/ was agreed in an issue first; no published ns/shapes/*/vN.ttl or decks/*/vN.ttl was edited; generated files were regenerated, not edited. (n/a: ns/ and decks/ are unchanged)
  • Breaking? Nothing in the public API breaks, or a commit says so (! and a BREAKING CHANGE: footer). npm run check:breaking sees a line of api/ that goes, but not a feature removed, nor a reader that reads less than before.
  • Pod data. Any change to what the app writes to a pod comes with its migration (docs/migrations.md). (n/a: both clients write the same documents with the same PATCH bodies)
  • Policy. Any change to an external rule the code follows (SM-2, the plural rules, a specification) is cited. (Solid-OIDC, IndexedDB and Web Locks in docs/standards.md; OpenID Connect Core in docs/solid-memo-client.md)
  • Licenses. New content is MIT, or a deck states its own license; a new file has its SPDX header (npm run lint:reuse), or a new deck its line in REUSE.toml; third-party content is credited.
  • Architecture. Imports follow docs/boundaries.md and the layers of docs/architecture.md.
  • Run. I ran the app (npm run dev) and tried the change, and considered the user journeys.
  • Authorship. I read and understand every line of this pull request, and answer for it, whatever tools helped write it (CONTRIBUTING.md).
  • Commits. Each commit is one logical change, in Conventional Commits form (type(scope): subject, ! and a BREAKING CHANGE: footer if it breaks something), with an imperative subject and a body that explains why (CONTRIBUTING.md).

ixuz added 4 commits October 27, 2026 23:46
client/sparqlUpdate.ts imported changesOf and localNameOf from the
Inrupt RDF module, so a second implementation of the client modules
could not use it without reaching that library. patchBody and
tripleLine now take the changes and the local-name reading they
spell, and the resource module and datasets.ts pass the RDF module's
own; the bodies are the same. The resource contract works out the
bodies it expects from the client it is given.

Refs: #331
The client modules' seams and contract were meant to let another
implementation take Inrupt's place. @solid-memo/solid-memo-client is
one, using no Inrupt package: the RDF data model and resources on n3
and jsonld-streaming-parser with plain fetch, Solid-OIDC sign-in on
oauth4webapi with a DPoP key WebCrypto keeps non-extractable in
IndexedDB, the public-read grant on WAC and ACP, and shacl's Turtle
reader. It passes the same contract suites, at 100% coverage.

Inrupt's clients stay the default. SOLID_CLIENT=solid-memo-client
makes the build and the tests take the new one: a Vite plugin
(scripts/solidClient.ts) resolves each client module to the module of
the same name in the new package, so no caller changes, and any other
value fails. Turbo hashes the choice and the package's sources. No
package imports the new one and it imports no Inrupt package, which
check:boundaries enforces; check:exports counts its exports as used
where the module they replace is.

Refs: #331
The second client is only worth keeping if it keeps working. Two jobs
run with SOLID_CLIENT=solid-memo-client: the solid, shacl,
composition and web packages' tests, and the pod tests on each
blocking server. They are advisory, so a failure shows on a pull
request without holding up a merge; the package's own tests, in
check, block as every package's do.

Refs: #331
A page of its own says what the second client is built on, how it
keeps a session, how it grants public read, where it differs from
Inrupt's and how it is tested; the vendor, boundary, sign-in,
privacy, standards and testing pages say where it fits.

Closes: #331
@ixuz ixuz added enhancement New feature or request dependencies Dependency versions, pins and updates ci/cd Countinuous integration and deployment labels Oct 27, 2026
@ixuz
ixuz added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 25d8f3a Oct 27, 2026
41 checks passed
@ixuz
ixuz deleted the alt-solid-client branch October 27, 2026 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd Countinuous integration and deployment dependencies Dependency versions, pins and updates enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A second Solid client, so the app doesn't rest on one vendor's libraries

1 participant