Skip to content

About

Linked Web Storage Server in JavaScript

Resources

Stars

1 star

Watchers

1 watching

Forks

Latest commit

 

History

23 Commits

Folders and files

Repository files navigation

LWS Server

Minimal Linked Web Storage Server

A lightweight, standalone implementation of the W3C Linked Web Storage (LWS) protocol in JavaScript.

License: AGPL v3

Features

  • ✅ Core LWS Protocol - GET, PUT, POST, DELETE, OPTIONS, HEAD
  • ✅ ETag Support - Concurrency control with If-Match/If-None-Match
  • ✅ CORS Enabled - Cross-origin resource sharing
  • ✅ Link Headers - LDP/LWS type headers
  • ✅ Container Support - Hierarchical storage with POST creation
  • ✅ Minimal Dependencies - Only 2 runtime dependencies
  • ✅ Fast Startup - < 100ms startup time
  • ✅ Small Footprint - ~1000 LOC, < 5MB node_modules
  • ✅ Embeddable - Use as Node.js module
  • ✅ Zero Config - Works out of the box

Installation

Global Installation (CLI)

npm install -g lws-server
lws-server --port 3126

Local Installation (Library)

npm install lws-server

Quick Start

CLI Usage

# Start server on default port 3126
lws-server

# Custom port and data directory
lws-server --port 8080 --root /var/data

# Quiet mode (no logging)
lws-server --quiet

CLI Options

-p, --port <number>     Port to listen on (default: 3126)
-h, --host <address>    Host to bind to (default: 0.0.0.0)
-r, --root <path>       Data directory (default: ./data)
-q, --quiet             Disable logging
--help                  Show help message

Programmatic Usage

import { createServer } from 'lws-server';

const server = createServer({
  port: 3126,
  root: './data',
  logger: true
});

await server.start();
console.log('LWS server running on http://localhost:3126');

HTTP API

Create Resource (PUT)

curl -X PUT http://localhost:3126/data.json \
  -H "Content-Type: application/json" \
  -d '{"hello": "world"}'

Create Resource (POST)

curl -X POST http://localhost:3126/ \
  -H "Content-Type: application/json" \
  -H "Slug: my-resource" \
  -d '{"created": "via POST"}'

Read Resource

curl http://localhost:3126/data.json

Update Resource

curl -X PUT http://localhost:3126/data.json \
  -H "Content-Type: application/json" \
  -d '{"updated": true}'

Delete Resource

curl -X DELETE http://localhost:3126/data.json

List Container

curl http://localhost:3126/

Returns JSON-LD:

{
  "@context": {
    "@vocab": "http://www.w3.org/ns/ldp#",
    "contains": {
      "@id": "http://www.w3.org/ns/ldp#contains",
      "@type": "@id"
    }
  },
  "@id": "http://localhost:3126/",
  "@type": ["Container", "BasicContainer", "Resource"],
  "contains": [
    { "@id": "http://localhost:3126/data.json" }
  ]
}

Create Container

curl -X POST http://localhost:3126/ \
  -H "Slug: my-folder" \
  -H "Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel=\"type\""

Concurrency Control

Safe Updates with If-Match

# Get current ETag
ETAG=$(curl -sI http://localhost:3126/data.json | grep -i etag | awk '{print $2}')

# Update only if ETag matches
curl -X PUT http://localhost:3126/data.json \
  -H "If-Match: $ETAG" \
  -H "Content-Type: application/json" \
  -d '{"safe": "update"}'

Prevent Overwrites with If-None-Match

# Create only if doesn't exist
curl -X PUT http://localhost:3126/new.json \
  -H "If-None-Match: *" \
  -H "Content-Type: application/json" \
  -d '{"create": "only"}'

Response Headers

All responses include LWS/LDP headers:

Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Link: <http://www.w3.org/ns/ldp#Container>; rel="type"
ETag: "1704963600000-42"
Access-Control-Allow-Origin: *
Allow: GET, HEAD, PUT, POST, DELETE, OPTIONS

Architecture

File Structure

lws-server/
├── index.js              # CLI entry point
├── lib/
│   ├── server.js         # Fastify setup
│   ├── handlers.js       # HTTP method handlers
│   ├── storage.js        # Filesystem operations
│   └── headers.js        # LWS/LDP headers
└── test/
    └── lws.test.js      # Integration tests

Dependencies

{
  "fastify": "^5.2.0",
  "fs-extra": "^11.2.0"
}

Total: 2 runtime dependencies (~50 packages with transitive dependencies)

Compare to full-featured servers:

  • JavaScriptSolidServer: 22 direct dependencies
  • Solid Community Server: 80+ dependencies

Use Cases

1. Development & Testing

Lightweight server for testing LWS clients:

import { createServer } from 'lws-server';

const server = createServer({ logger: false, port: 0 });
await server.listen({ port: 0 });

// Run tests against server
// ...

await server.close();

2. Embedding in Applications

import express from 'express';
import { createServer } from 'lws-server';

const app = express();

// Mount LWS server at /storage
const lws = createServer({ root: './storage' });
app.use('/storage', lws);

app.listen(3126);

3. Microservices

Use as lightweight storage layer:

// service.js
import { createServer } from 'lws-server';

const storage = createServer({
  port: 8080,
  root: process.env.DATA_DIR,
  logger: false
});

await storage.start();

4. Education

Learn LWS protocol without complex features:

git clone https://github.com/linkedwebstorage/lws-server
cd lws-server
npm install
node index.js

Then explore lib/handlers.js (~300 LOC) to understand LWS operations.

Comparison

Feature lws-server JSS Solid Community Server
LOC ~1000 ~8000 ~20000+
Dependencies 2 22 80+
Startup < 100ms ~500ms ~2s
Memory ~30MB ~150MB ~300MB
Protocols LWS LDP, LWS, OIDC, AP, Nostr LDP, Solid-OIDC
Auth None 5 methods Solid-OIDC
Features CRUD only 20+ Full Solid spec
Best For Embedding, testing Multi-protocol pods Production Solid

What's NOT Included

This is a minimal server. Not included:

  • ❌ Authentication/Authorization (no login, tokens, or ACLs)
  • ❌ Solid-OIDC
  • ❌ Content negotiation (Turtle ↔ JSON-LD)
  • ❌ N3 Patch or SPARQL Update
  • ❌ WebSocket notifications
  • ❌ Storage quotas
  • ❌ Multi-user account management

For full-featured servers, see:

Testing

npm install
npm test

Tests use Node.js built-in test runner (no external dependencies).

Environment Variables

DATA_ROOT=/var/data  # Data directory path

LWS Protocol Compliance

This server implements:

  • ✅ GET - Read resources and containers
  • ✅ PUT - Create or update resources
  • ✅ POST - Create resources with server-assigned URIs
  • ✅ DELETE - Remove resources
  • ✅ HEAD - Get metadata without body
  • ✅ OPTIONS - CORS preflight
  • ✅ ETags - Concurrency control
  • ✅ Link headers - Resource type metadata

Status: Implements core CRUD operations per LWS Protocol PR #37.

Not implemented (future LWS features):

  • ⚠️ Linkset endpoints (/resource;linkset)
  • ⚠️ JSON Merge Patch for metadata

Related Projects

Contributing

Contributions welcome! This project aims to stay minimal - only core LWS protocol features.

Guidelines:

  • Keep total LOC < 1500
  • Keep dependencies < 3 runtime deps
  • No authentication (out of scope)
  • No content negotiation (out of scope)

License

AGPL-3.0 © Melvin Carvalho

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Acknowledgments

Extracted and simplified from JavaScriptSolidServer.

Built for the W3C Linked Web Storage community.

About

Linked Web Storage Server in JavaScript

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages