javascript-solid-server 0.0.32 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "javascript-solid-server",
3
- "version": "0.0.32",
3
+ "version": "0.0.33",
4
4
  "description": "A minimal, fast Solid server",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -125,12 +125,11 @@ export async function handlePost(request, reply) {
125
125
  * Create pod directory structure (reusable for registration)
126
126
  * @param {string} name - Pod name (username)
127
127
  * @param {string} webId - User's WebID URI
128
- * @param {string} baseUrl - Base URL (without trailing slash)
128
+ * @param {string} podUri - Pod root URI (e.g., https://alice.example.com/ or https://example.com/alice/)
129
+ * @param {string} issuer - OIDC issuer URI
129
130
  */
130
- export async function createPodStructure(name, webId, baseUrl) {
131
+ export async function createPodStructure(name, webId, podUri, issuer) {
131
132
  const podPath = `/${name}/`;
132
- const podUri = `${baseUrl}/${name}/`;
133
- const issuer = baseUrl + '/';
134
133
 
135
134
  // Create pod directory structure
136
135
  await storage.createContainer(podPath);
@@ -253,7 +252,7 @@ export async function handleCreatePod(request, reply) {
253
252
 
254
253
  try {
255
254
  // Use shared pod creation function
256
- await createPodStructure(name, webId, baseUri);
255
+ await createPodStructure(name, webId, podUri, issuer);
257
256
  } catch (err) {
258
257
  console.error('Pod creation error:', err);
259
258
  // Cleanup on failure
@@ -146,6 +146,42 @@ export async function handleGet(request, reply) {
146
146
  return reply.type('text/html').send(html);
147
147
  }
148
148
 
149
+ // Check if Turtle/N3 format is requested via content negotiation
150
+ const acceptHeader = request.headers.accept || '';
151
+ const wantsTurtle = connegEnabled && (
152
+ acceptHeader.includes('text/turtle') ||
153
+ acceptHeader.includes('text/n3') ||
154
+ acceptHeader.includes('application/n-triples')
155
+ );
156
+
157
+ if (wantsTurtle) {
158
+ // Convert container JSON-LD to Turtle
159
+ try {
160
+ const { content: turtleContent } = await fromJsonLd(
161
+ jsonLd,
162
+ 'text/turtle',
163
+ resourceUrl,
164
+ true
165
+ );
166
+
167
+ const headers = getAllHeaders({
168
+ isContainer: true,
169
+ etag: stats.etag,
170
+ contentType: 'text/turtle',
171
+ origin,
172
+ resourceUrl,
173
+ connegEnabled
174
+ });
175
+ headers['Vary'] = 'Accept';
176
+
177
+ Object.entries(headers).forEach(([k, v]) => reply.header(k, v));
178
+ return reply.send(turtleContent);
179
+ } catch (err) {
180
+ // Fall through to JSON-LD if conversion fails
181
+ console.error('Failed to convert container to Turtle:', err.message);
182
+ }
183
+ }
184
+
149
185
  const headers = getAllHeaders({
150
186
  isContainer: true,
151
187
  etag: stats.etag,
@@ -196,7 +232,9 @@ export async function handleGet(request, reply) {
196
232
  if (connegEnabled) {
197
233
  const contentStr = content.toString();
198
234
  const acceptHeader = request.headers.accept || '';
199
- const wantsTurtle = acceptHeader.includes('text/turtle') ||
235
+ // Serve Turtle if: URL ends with .ttl OR Accept header requests it
236
+ const wantsTurtle = urlPath.endsWith('.ttl') ||
237
+ acceptHeader.includes('text/turtle') ||
200
238
  acceptHeader.includes('text/n3') ||
201
239
  acceptHeader.includes('application/n-triples');
202
240
 
@@ -233,7 +271,8 @@ export async function handleGet(request, reply) {
233
271
  // Plain JSON-LD file
234
272
  try {
235
273
  const jsonLd = JSON.parse(contentStr);
236
- const targetType = selectContentType(acceptHeader, connegEnabled);
274
+ // Use Turtle if URL ends with .ttl, otherwise use Accept header preference
275
+ const targetType = wantsTurtle ? 'text/turtle' : selectContentType(acceptHeader, connegEnabled);
237
276
  const { content: outputContent, contentType: outputType } = await fromJsonLd(
238
277
  jsonLd,
239
278
  targetType,
@@ -355,9 +355,20 @@ export async function handleRegisterPost(request, reply, issuer) {
355
355
 
356
356
  try {
357
357
  // Build URLs - WebID follows standard Solid convention: /profile/card#me
358
+ const subdomainsEnabled = request.subdomainsEnabled;
359
+ const baseDomain = request.baseDomain;
358
360
  const baseUrl = issuer.endsWith('/') ? issuer.slice(0, -1) : issuer;
359
- const podUri = `${baseUrl}/${username}/`;
360
- const webId = `${podUri}profile/card#me`;
361
+
362
+ let podUri, webId;
363
+ if (subdomainsEnabled && baseDomain) {
364
+ // Subdomain mode: alice.example.com/profile/card#me
365
+ podUri = `${request.protocol}://${username}.${baseDomain}/`;
366
+ webId = `${podUri}profile/card#me`;
367
+ } else {
368
+ // Path mode: example.com/alice/profile/card#me
369
+ podUri = `${baseUrl}/${username}/`;
370
+ webId = `${podUri}profile/card#me`;
371
+ }
361
372
 
362
373
  // Check if pod already exists
363
374
  const podPath = `${username}/`;
@@ -367,7 +378,7 @@ export async function handleRegisterPost(request, reply, issuer) {
367
378
  }
368
379
 
369
380
  // Create pod structure
370
- await createPodStructure(username, webId, baseUrl);
381
+ await createPodStructure(username, webId, podUri, issuer);
371
382
 
372
383
  // Create account
373
384
  await createAccount({
@@ -90,7 +90,7 @@ export function getCorsHeaders(origin) {
90
90
  return {
91
91
  'Access-Control-Allow-Origin': origin || '*',
92
92
  'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS',
93
- 'Access-Control-Allow-Headers': 'Accept, Authorization, Content-Type, If-Match, If-None-Match, Link, Slug, Origin',
93
+ 'Access-Control-Allow-Headers': 'Accept, Authorization, Content-Type, DPoP, If-Match, If-None-Match, Link, Slug, Origin',
94
94
  'Access-Control-Expose-Headers': 'Accept-Patch, Accept-Post, Allow, Content-Type, ETag, Link, Location, Updates-Via, WAC-Allow',
95
95
  'Access-Control-Allow-Credentials': 'true',
96
96
  'Access-Control-Max-Age': '86400'