javascript-solid-server 0.0.124 → 0.0.126

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.
@@ -335,7 +335,10 @@
335
335
  "Bash(TORRENT=/home/melvin/.claude/projects/-home-melvin-remote-github-com-JavaScriptSolidServer-JavaScriptSolidServer/a05da419-92b7-4056-93b8-e97b2035d4ae/tool-results/webfetch-1774004425803-fce7mx.bin npx -y parse-torrent $TORRENT)",
336
336
  "Bash(gh issue:*)",
337
337
  "Bash(sed -i 's|Settings/|settings/|g' src/server.js src/handlers/container.js src/webid/profile.js)",
338
- "Bash(sed -i 's|// Settings folder|// settings folder|' src/handlers/container.js)"
338
+ "Bash(sed -i 's|// Settings folder|// settings folder|' src/handlers/container.js)",
339
+ "WebFetch(domain:www.x402.org)",
340
+ "Bash(jss start:*)",
341
+ "Read(//tmp/**)"
339
342
  ]
340
343
  }
341
344
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "javascript-solid-server",
3
- "version": "0.0.124",
3
+ "version": "0.0.126",
4
4
  "description": "A minimal, fast Solid server",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -24,6 +24,8 @@ import { generateDatabrowserHtml, generateModuleDatabrowserHtml } from '../mashl
24
24
  * @returns {string} Normalized resource URL
25
25
  */
26
26
  function buildResourceUrl(request, urlPath) {
27
+ // Use request.headers.host (includes port) instead of request.hostname (strips port)
28
+ const host = request.headers.host || request.hostname;
27
29
  if (request.subdomainsEnabled && request.baseDomain &&
28
30
  request.hostname === request.baseDomain && !request.podName) {
29
31
  const pathMatch = urlPath.match(/^\/([^/]+)(\/.*)?$/);
@@ -33,7 +35,7 @@ function buildResourceUrl(request, urlPath) {
33
35
  return `${request.protocol}://${podName}.${request.baseDomain}${remainder}`;
34
36
  }
35
37
  }
36
- return `${request.protocol}://${request.hostname}${urlPath}`;
38
+ return `${request.protocol}://${host}${urlPath}`;
37
39
  }
38
40
 
39
41
  /**
@@ -180,7 +182,7 @@ function getErrorPage(statusCode, isAuthenticated, request) {
180
182
  ? "This resource is protected. You'll need to sign in to continue."
181
183
  : "You're signed in, but you don't have permission to view this resource.";
182
184
 
183
- const baseUrl = `${request.protocol}://${request.hostname}`;
185
+ const baseUrl = `${request.protocol}://${request.headers.host || request.hostname}`;
184
186
 
185
187
  return `<!DOCTYPE html>
186
188
  <html lang="en">
@@ -163,15 +163,26 @@ async function checkAuthorizations(authorizations, targetUrl, agentWebId, requir
163
163
  c.type === 'PaymentCondition' || c.type === 'https://webacl.org/ns#PaymentCondition'
164
164
  );
165
165
  if (paymentCondition) {
166
- // Check if agent has sufficient balance
167
- const cost = parseInt(paymentCondition.amount, 10) || 0;
166
+ const parsed = parseInt(paymentCondition.amount, 10);
167
+ const cost = Number.isNaN(parsed) ? -1 : parsed;
168
168
  const currency = paymentCondition.currency || 'sat';
169
- if (agentWebId && cost > 0) {
169
+
170
+ // Skip invalid amounts
171
+ if (cost < 0) continue;
172
+
173
+ if (agentWebId) {
170
174
  try {
171
175
  const ledger = await readLedger();
176
+
177
+ // Zero-cost gate: verify they have a ledger entry (have deposited at some point)
178
+ if (cost === 0) {
179
+ const hasEntry = ledger.entries?.some(e => e.url === agentWebId);
180
+ if (hasEntry) return { allowed: true };
181
+ }
182
+
183
+ // Paid access: check balance and deduct
172
184
  const balance = getBalance(ledger, agentWebId);
173
- if (balance >= cost) {
174
- // Deduct and grant access
185
+ if (cost > 0 && balance >= cost) {
175
186
  debit(ledger, agentWebId, cost, currency === 'sats' ? 'sat' : currency);
176
187
  const { writeLedger } = await import('../webledger.js');
177
188
  await writeLedger(ledger);
package/test/wac.test.js CHANGED
@@ -428,6 +428,30 @@ describe('WAC Conditions', () => {
428
428
  assert.strictEqual(auths[0].conditions[0].type, 'UnknownFutureCondition');
429
429
  });
430
430
 
431
+ it('should parse zero-cost PaymentCondition', async () => {
432
+ const acl = {
433
+ '@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
434
+ '@graph': [{
435
+ '@id': '#gate',
436
+ '@type': 'acl:Authorization',
437
+ 'acl:agentClass': { '@id': 'acl:AuthenticatedAgent' },
438
+ 'acl:accessTo': { '@id': 'https://alice.example/members/' },
439
+ 'acl:mode': [{ '@id': 'acl:Read' }],
440
+ 'acl:condition': {
441
+ '@type': 'PaymentCondition',
442
+ 'amount': '0',
443
+ 'currency': 'sats'
444
+ }
445
+ }]
446
+ };
447
+
448
+ const auths = await parseAcl(JSON.stringify(acl), 'https://alice.example/members/.acl');
449
+ const condition = auths[0].conditions[0];
450
+
451
+ assert.strictEqual(condition.type, 'PaymentCondition');
452
+ assert.strictEqual(condition.amount, '0');
453
+ });
454
+
431
455
  it('should parse PaymentCondition with all fields', async () => {
432
456
  const acl = {
433
457
  '@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },