Skip to content

Conneg: recognise .acl and .meta as RDF (#294) — unblocks umai#296

Merged
melvincarvalho merged 1 commit into
JavaScriptSolidServer:gh-pagesfrom
melvincarvalho:issue-294-meta-acl-conneg
Apr 22, 2026
Merged

Conneg: recognise .acl and .meta as RDF (#294) — unblocks umai#296
melvincarvalho merged 1 commit into
JavaScriptSolidServer:gh-pagesfrom
melvincarvalho:issue-294-meta-acl-conneg

Conversation

@melvincarvalho

Copy link
Copy Markdown
Contributor

Fixes #294.

Summary

`getContentType()` in `src/utils/url.js` is extension-based, but `path.extname()` returns `''` for leading-dot names like `.acl` / `.meta` (node treats them as dotfiles). Both were falling through to `application/octet-stream`, which `isRdfContentType()` rejects, so `handleGet`'s conneg branch never ran for them.

Visible break: Turtle-native clients (umai, Soukai-based apps, older Solid tooling) fetching `/.meta` got JSON-LD back and errored with `MalformedSolidDocumentError: Malformed Turtle document — Expected entity but got { on line 2`. Hit today against ewingson's `test.solidweb.app` pod (JSS 0.0.144, `conneg: true`).

Latent twin: same bug applies to `.acl`. Hasn't shown up yet because (a) JSS's internal `parseAcl()` is forgiving (tries JSON then Turtle), and (b) most clients read `wac-allow` instead of fetching `.acl` directly. But any strict-Turtle ACL editor pointed at any existing JSS pod would hit the same parser error.

Change

One basename check in `getContentType`:

```js
const base = path.basename(filePath);
if (base === '.acl' || base === '.meta') return 'application/ld+json';
```

Mapped to `application/ld+json` (not `text/turtle`) because that's the format JSS already writes them in (`serializeAcl()`, `createPodStructure()`). Conneg handles translation for Turtle clients through `handleGet`'s existing JSON-LD-to-Turtle path, and `handlePut` already converts incoming Turtle to JSON-LD before storing when `--conneg` is on.

Zero migration: existing pods keep their JSON-LD-stored `.acl` / `.meta` files on disk. They become Turtle-servable immediately, no rewrite.

Round-trip table

Client Request Before After
umai `GET .meta Accept: text/turtle` JSON-LD (parser error) Turtle ✓
umai `PUT .meta Content-Type: text/turtle` Stored as Turtle bytes Converted to JSON-LD, stored ✓
pilot `GET .meta Accept: application/ld+json` JSON-LD raw JSON-LD raw (unchanged) ✓

Files

  • `src/utils/url.js` — 1 basename check in `getContentType`, 1 comment block.
  • `test/url.test.js` — new `getContentType` describe block (6 cases; covers extension mapping, dotfile mapping, and a guard that non-dotfile paths containing "acl" aren't mistaken for ACL files).
  • `test/conneg.test.js` — new `Solid convention dotfiles (Conneg: .meta and .acl files are not recognized as RDF, break Turtle-native clients #294)` block with 3 integration cases against a running `--conneg` server: GET .meta default → ld+json; GET .meta Accept turtle → turtle (the umai case, with an explicit regression-guard assertion that the body doesn't look like JSON); PUT turtle .meta → round-trips to JSON-LD.

Test plan

  • `node --test test/url.test.js` — 17/17 pass.
  • `node --test test/conneg.test.js` — 18/18 pass.
  • `npm test` — 407/407 pass (was 398 + 9 new).
  • Manual: point umai at `test.solidweb.app` after deploy. Should no longer `{` on line 2.

Relation to #295

#295 proposes a sibling tightening: when `--conneg` is off, reject non-JSON-LD PUTs with 415 instead of silently storing corrupted bytes. That's a design-ier purity fix; deliberately kept separate from this PR so the real interop blocker (umai) ships first without getting stalled on 415-response bikeshed.

…Server#294)

getContentType() in src/utils/url.js is extension-based, but
path.extname() returns '' for leading-dot names like '.acl' /
'.meta' (node treats them as dotfiles, not extensions). Both
fell through to application/octet-stream, which isRdfContentType()
rejects, so handleGet's conneg branch never ran for them.

Effect: Turtle-native clients (umai, Soukai-based apps, older
Solid tooling) fetching <container>/.meta got JSON-LD back and
errored with 'Malformed Turtle document — Expected entity but
got { on line 2'. Hit today against ewingson's test.solidweb.app
pod.

Fix: one basename check in getContentType mapping '.acl' / '.meta'
to application/ld+json — the format JSS already writes them in
(via serializeAcl(), createPodStructure(), etc.). Conneg then
handles translation for Turtle clients through handleGet's
existing JSON-LD-to-Turtle path, and handlePut already converts
incoming Turtle to JSON-LD before storing when --conneg is on.

Zero migration: existing pods on disk stay as-is and become
Turtle-servable immediately.

Tests:

- test/url.test.js: new 'getContentType' describe block — 6 cases
  (extension mapping, dotfile mapping, the 'acl-in-filename isn't
  an ACL file' guard).
- test/conneg.test.js: new 'Solid convention dotfiles (JavaScriptSolidServer#294)'
  block — 3 integration cases against a running server (GET .meta
  default → ld+json, GET .meta with Accept: turtle → turtle, PUT
  turtle .meta → round-trips to JSON-LD).

Full suite: 407/407 pass (was 398 + 9 new).

The sibling tightening — reject non-JSON-LD PUTs with 415 when
--conneg is off — is tracked separately as JavaScriptSolidServer#295 to avoid conflating
a visible interop break with a design-ier purity fix.

Fixes JavaScriptSolidServer#294
@melvincarvalho
melvincarvalho requested a review from Copilot April 22, 2026 11:17

Copilot AI 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.

Pull request overview

Fixes Solid conneg for convention dotfiles (.acl, .meta) by ensuring they’re recognized as RDF (JSON-LD) despite Node’s path.extname() returning '' for leading-dot filenames, which previously prevented the conneg branch from running for these resources.

Changes:

  • Update getContentType() to special-case basenames .acl and .meta as application/ld+json.
  • Add unit tests for getContentType() covering standard extension mapping and the dotfile regression.
  • Add conneg integration tests validating .meta GET/PUT round-trips with Accept: text/turtle and JSON-LD defaults.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/utils/url.js Recognizes .acl/.meta via basename and returns JSON-LD content-type so conneg can apply.
test/url.test.js Adds unit coverage for getContentType() including .acl/.meta regression cases.
test/conneg.test.js Adds integration coverage ensuring .meta negotiates to Turtle and Turtle PUTs are stored as JSON-LD under conneg.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@melvincarvalho
melvincarvalho merged commit a0a9ccd into JavaScriptSolidServer:gh-pages Apr 22, 2026
4 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.

Conneg: .meta and .acl files are not recognized as RDF, break Turtle-native clients

2 participants