|
1 | | -# Vision |
| 1 | +# JavaScript Solid Server |
2 | 2 |
|
3 | | -The goal of this project is to create a hyper-modern, performant, and minimalist JavaScript Solid server. While drawing inspiration from Node Solid Server (NSS), this new implementation will address its shortcomings and prioritize scalability, modularity, and developer usability. |
| 3 | +A minimal, fast, JSON-LD native Solid server. |
4 | 4 |
|
5 | | -## Key Objectives |
| 5 | +## Philosophy: JSON-LD First |
6 | 6 |
|
7 | | -- **Performance First:** Capable of handling enterprise-scale loads, targeting thousands to millions of users. |
8 | | -- **Minimalist Design:** Remove unused and experimental features; focus on what matters most. |
9 | | -- **Modularity:** Clear separation of identity, authentication, storage, and onboarding. |
10 | | -- **Developer Friendly:** Clean, well-documented, and extensible codebase that adheres to the Solid specification. |
11 | | -- **Modern Tooling:** Leverage async/await, native modules, fast HTTP servers like Fastify, and cutting-edge JavaScript runtimes. |
12 | | -- **HTTP Simplicity:** Prioritize simple HTTP/1.1 compatibility for maximum interoperability. |
13 | | -- **Frontend Agnostic:** Work with any frontend or application layer via standardized APIs. |
14 | | -- **Testable and CI Ready:** Fully integrated with Solid test suites and modern CI/CD pipelines. |
| 7 | +This is a **JSON-LD native implementation**. Unlike traditional Solid servers that treat Turtle as the primary format and convert to/from it, this server: |
15 | 8 |
|
16 | | ---- |
| 9 | +- **Stores everything as JSON-LD** - No RDF parsing overhead for standard operations |
| 10 | +- **Serves JSON-LD by default** - Modern web applications can consume responses directly |
| 11 | +- **Content negotiation is optional** - Enable Turtle support with `{ conneg: true }` when needed |
| 12 | +- **Fast by design** - Skip the RDF parsing tax when you don't need it |
17 | 13 |
|
18 | | -# ARCHITECTURE |
| 14 | +### Why JSON-LD First? |
19 | 15 |
|
20 | | -## Overview |
| 16 | +1. **Performance**: JSON parsing is native to JavaScript - no external RDF libraries needed for basic operations |
| 17 | +2. **Simplicity**: JSON-LD is valid JSON - works with any JSON tooling |
| 18 | +3. **Web-native**: Browsers and web apps understand JSON natively |
| 19 | +4. **Semantic web ready**: JSON-LD is a W3C standard RDF serialization |
21 | 20 |
|
22 | | -The architecture is inspired by NSS but modernized and streamlined. Each subsystem is designed to operate independently and follow the single-responsibility principle. |
| 21 | +### When to Enable Content Negotiation |
23 | 22 |
|
24 | | -### Components |
| 23 | +Enable `conneg: true` when: |
| 24 | +- Interoperating with Turtle-based Solid apps |
| 25 | +- Serving data to legacy Solid clients |
| 26 | +- Running conformance tests that require Turtle support |
25 | 27 |
|
26 | | -- **HTTP Layer** |
| 28 | +```javascript |
| 29 | +import { createServer } from './src/server.js'; |
27 | 30 |
|
28 | | - - Fastify server |
29 | | - - Routing and middleware based on HTTP verbs and Solid operations |
30 | | - - Blazingly fast, with benchmarks from the start |
| 31 | +// Default: JSON-LD only (fast) |
| 32 | +const server = createServer(); |
31 | 33 |
|
32 | | -- **Identity Provider (IDP)** |
33 | | - |
34 | | - - Handles Pod based WebIDs |
35 | | - - Handles external WebIDs |
36 | | - - Minimal by default, extendable via plugins |
37 | | - |
38 | | -- **Authenticaion Module (AUthn)** |
39 | | - |
40 | | - - Handles WebID-based authentication, including WebID-TLS |
41 | | - - OIDC-compliant with modular Authentication |
42 | | - - Single sign-on including WebID-TLS |
43 | | - |
44 | | -- **Authorization Module (Authz)** |
45 | | - |
46 | | - - Supports Web Access Control (WAC) |
47 | | - - Token-based permissions model |
48 | | - - Modular Authorization system |
49 | | - |
50 | | -- **Storage Engine** |
51 | | - |
52 | | - - Modular backend adapters (e.g. file system, S3, memory) |
53 | | - - POD-level quota management (optional) |
54 | | - - Interoperable with existing Cloud |
55 | | - |
56 | | -- **Account and Onboarding** |
57 | | - - API-first registration |
58 | | - - Public, private, invite modes |
59 | | - - Extensible account templates |
60 | | - |
61 | | -### Deployment Model |
62 | | - |
63 | | -- Works as a single binary or serverless function |
64 | | -- Container-friendly (Docker, Deno, etc.) |
65 | | -- CLI for local dev setup and testing |
66 | | - |
67 | | -### Separation of Concerns |
68 | | - |
69 | | -- Each subsystem lives in its own module/package |
70 | | -- Clear boundaries between IDP and storage |
71 | | -- Frontend-independent API endpoints |
72 | | - |
73 | | -### Compatibility |
74 | | - |
75 | | -- Solid-compliant, LWS Compliant |
76 | | -- API parity with NSS where applicable |
77 | | -- API parity with CSS where applicable |
78 | | - |
79 | | ---- |
80 | | - |
81 | | -# MVP Implementation |
| 34 | +// With Turtle support (for interoperability) |
| 35 | +const serverWithConneg = createServer({ conneg: true }); |
| 36 | +``` |
82 | 37 |
|
83 | | -This is a minimal viable product (MVP) implementation of the JavaScriptSolid server. It includes the core components needed to demonstrate the concept while omitting some of the more complex features for simplicity. |
| 38 | +## Features |
| 39 | + |
| 40 | +### Implemented (v0.0.8) |
| 41 | + |
| 42 | +- **LDP CRUD Operations** - GET, PUT, POST, DELETE, HEAD |
| 43 | +- **N3 Patch** - Solid's native patch format for RDF updates |
| 44 | +- **Container Management** - Create, list, and manage containers |
| 45 | +- **Multi-user Pods** - Create pods at `/<username>/` |
| 46 | +- **WebID Profiles** - JSON-LD structured data in HTML at pod root |
| 47 | +- **Web Access Control (WAC)** - `.acl` file-based authorization |
| 48 | +- **Solid-OIDC Resource Server** - Accept DPoP-bound access tokens from external IdPs |
| 49 | +- **Simple Auth Tokens** - Built-in token authentication for development |
| 50 | +- **Content Negotiation** - Optional Turtle <-> JSON-LD conversion |
| 51 | +- **CORS Support** - Full cross-origin resource sharing |
| 52 | + |
| 53 | +### HTTP Methods |
| 54 | + |
| 55 | +| Method | Support | |
| 56 | +|--------|---------| |
| 57 | +| GET | Full - Resources and containers | |
| 58 | +| HEAD | Full | |
| 59 | +| PUT | Full - Create/update resources | |
| 60 | +| POST | Full - Create in containers | |
| 61 | +| DELETE | Full | |
| 62 | +| PATCH | N3 Patch format | |
| 63 | +| OPTIONS | Full with CORS | |
84 | 64 |
|
85 | 65 | ## Getting Started |
86 | 66 |
|
87 | 67 | ### Prerequisites |
88 | 68 |
|
89 | | -- Node.js 18 or higher |
| 69 | +- Node.js 18+ |
90 | 70 |
|
91 | 71 | ### Installation |
92 | 72 |
|
93 | 73 | ```bash |
94 | | -# Clone the repository |
95 | | -git clone https://github.com/yourusername/javascript-solid-server.git |
96 | | -cd javascript-solid-server |
97 | | - |
98 | | -# Install dependencies |
99 | 74 | npm install |
100 | 75 | ``` |
101 | 76 |
|
102 | | -### Running the Server |
| 77 | +### Running |
103 | 78 |
|
104 | 79 | ```bash |
105 | | -# Start the server |
| 80 | +# Start server (default port 3000) |
106 | 81 | npm start |
107 | | -``` |
108 | 82 |
|
109 | | -The server will be available at http://localhost:3000 by default. |
| 83 | +# Development mode with watch |
| 84 | +npm dev |
| 85 | +``` |
110 | 86 |
|
111 | | -## Features Included in MVP |
| 87 | +### Creating a Pod |
112 | 88 |
|
113 | | -- **HTTP Server**: Based on Fastify for high performance |
114 | | -- **Basic Identity Provider**: Simple user registration and login with JWT tokens |
115 | | -- **Simple Authorization**: Basic implementation of WAC (Web Access Control) |
116 | | -- **File-based Storage**: Local filesystem storage for Solid resources |
117 | | -- **Basic Solid Protocol Support**: GET, PUT, DELETE, PATCH, and HEAD operations |
| 89 | +```bash |
| 90 | +curl -X POST http://localhost:3000/.pods \ |
| 91 | + -H "Content-Type: application/json" \ |
| 92 | + -d '{"name": "alice"}' |
| 93 | +``` |
118 | 94 |
|
119 | | -## Features Omitted in MVP (to be added later) |
| 95 | +Response: |
| 96 | +```json |
| 97 | +{ |
| 98 | + "name": "alice", |
| 99 | + "webId": "http://localhost:3000/alice/#me", |
| 100 | + "podUri": "http://localhost:3000/alice/", |
| 101 | + "token": "eyJ..." |
| 102 | +} |
| 103 | +``` |
120 | 104 |
|
121 | | -1. WebID-TLS Authentication |
122 | | -2. Full OIDC implementation |
123 | | -3. Advanced WAC features and ACL file parsing |
124 | | -4. Quotas and resource limits |
125 | | -5. Advanced container management |
126 | | -6. SPARQL and N3 Patch support |
127 | | -7. Notification systems |
| 105 | +### Using the Pod |
128 | 106 |
|
129 | | -## API Usage Examples |
| 107 | +```bash |
| 108 | +# Read public profile |
| 109 | +curl http://localhost:3000/alice/ |
130 | 110 |
|
131 | | -### User Registration |
| 111 | +# Write to pod (with token) |
| 112 | +curl -X PUT http://localhost:3000/alice/public/data.json \ |
| 113 | + -H "Authorization: Bearer YOUR_TOKEN" \ |
| 114 | + -H "Content-Type: application/ld+json" \ |
| 115 | + -d '{"@id": "#data", "http://example.org/value": 42}' |
132 | 116 |
|
133 | | -```bash |
134 | | -curl -X POST http://localhost:3000/register \ |
135 | | - -H "Content-Type: application/json" \ |
136 | | - -d '{"username": "alice", "password": "secret", "email": "alice@example.com"}' |
| 117 | +# Read back |
| 118 | +curl http://localhost:3000/alice/public/data.json |
137 | 119 | ``` |
138 | 120 |
|
139 | | -### Login |
| 121 | +### PATCH with N3 |
140 | 122 |
|
141 | 123 | ```bash |
142 | | -curl -X POST http://localhost:3000/login \ |
143 | | - -H "Content-Type: application/json" \ |
144 | | - -d '{"username": "alice", "password": "secret"}' |
| 124 | +curl -X PATCH http://localhost:3000/alice/public/data.json \ |
| 125 | + -H "Authorization: Bearer YOUR_TOKEN" \ |
| 126 | + -H "Content-Type: text/n3" \ |
| 127 | + -d '@prefix solid: <http://www.w3.org/ns/solid/terms#>. |
| 128 | + _:patch a solid:InsertDeletePatch; |
| 129 | + solid:inserts { <#data> <http://example.org/name> "Updated" }.' |
145 | 130 | ``` |
146 | 131 |
|
147 | | -### Accessing Resources |
| 132 | +## Pod Structure |
148 | 133 |
|
149 | | -```bash |
150 | | -# Get a resource |
151 | | -curl -X GET http://localhost:3000/alice/profile \ |
152 | | - -H "Authorization: Bearer YOUR_TOKEN_HERE" |
153 | | - |
154 | | -# Create or update a resource |
155 | | -curl -X PUT http://localhost:3000/alice/profile \ |
156 | | - -H "Authorization: Bearer YOUR_TOKEN_HERE" \ |
157 | | - -H "Content-Type: text/turtle" \ |
158 | | - -d '@prefix foaf: <http://xmlns.com/foaf/0.1/>. <#me> a foaf:Person; foaf:name "Alice".' |
| 134 | +``` |
| 135 | +/alice/ |
| 136 | +├── index.html # WebID profile (HTML with JSON-LD) |
| 137 | +├── .acl # Root ACL (owner + public read) |
| 138 | +├── inbox/ # Notifications (public append) |
| 139 | +│ └── .acl |
| 140 | +├── public/ # Public files |
| 141 | +├── private/ # Private files (owner only) |
| 142 | +│ └── .acl |
| 143 | +└── settings/ # User preferences (owner only) |
| 144 | + ├── .acl |
| 145 | + ├── prefs |
| 146 | + ├── publicTypeIndex |
| 147 | + └── privateTypeIndex |
159 | 148 | ``` |
160 | 149 |
|
161 | | -## Performance Benchmarking |
| 150 | +## Authentication |
162 | 151 |
|
163 | | -This project includes a comprehensive benchmarking tool to measure server performance under various loads. |
| 152 | +### Simple Tokens (Development) |
164 | 153 |
|
165 | | -### Running the Benchmark |
| 154 | +Use the token returned from pod creation: |
166 | 155 |
|
167 | 156 | ```bash |
168 | | -# Make sure the server is running in a separate terminal |
169 | | -npm start |
170 | | - |
171 | | -# In another terminal, run the benchmark |
172 | | -npm run benchmark |
| 157 | +curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3000/alice/private/ |
173 | 158 | ``` |
174 | 159 |
|
175 | | -The benchmark will: |
| 160 | +### Solid-OIDC (Production) |
| 161 | + |
| 162 | +The server accepts DPoP-bound access tokens from external Solid identity providers: |
| 163 | + |
| 164 | +```bash |
| 165 | +curl -H "Authorization: DPoP ACCESS_TOKEN" \ |
| 166 | + -H "DPoP: DPOP_PROOF" \ |
| 167 | + http://localhost:3000/alice/private/ |
| 168 | +``` |
176 | 169 |
|
177 | | -1. Create multiple test users |
178 | | -2. Execute various operations (register, login, read, write, delete) |
179 | | -3. Measure response times for each operation type |
180 | | -4. Test different concurrency levels (1, 5, 10, 50, 100 users) |
181 | | -5. Calculate throughput (operations per second) |
| 170 | +## Configuration |
182 | 171 |
|
183 | | -### Visualizing Results |
| 172 | +```javascript |
| 173 | +createServer({ |
| 174 | + logger: true, // Enable Fastify logging (default: true) |
| 175 | + conneg: false // Enable content negotiation (default: false) |
| 176 | +}); |
| 177 | +``` |
184 | 178 |
|
185 | | -After running the benchmark, you can generate a visual report: |
| 179 | +## Running Tests |
186 | 180 |
|
187 | 181 | ```bash |
188 | | -# Generate an HTML report with charts |
189 | | -npm run visualize benchmark-report-[timestamp].json |
| 182 | +npm test |
190 | 183 | ``` |
191 | 184 |
|
192 | | -Open the generated HTML file in a browser to see: |
| 185 | +Currently passing: **105 tests** |
| 186 | + |
| 187 | +## Project Structure |
193 | 188 |
|
194 | | -- Average response times for each operation type |
195 | | -- Throughput metrics at different concurrency levels |
196 | | -- Visual charts for easy performance analysis |
| 189 | +``` |
| 190 | +src/ |
| 191 | +├── index.js # Entry point |
| 192 | +├── server.js # Fastify setup |
| 193 | +├── handlers/ |
| 194 | +│ ├── resource.js # GET, PUT, DELETE, HEAD, PATCH |
| 195 | +│ └── container.js # POST, pod creation |
| 196 | +├── storage/ |
| 197 | +│ └── filesystem.js # File operations |
| 198 | +├── auth/ |
| 199 | +│ ├── middleware.js # Auth hook |
| 200 | +│ ├── token.js # Simple token auth |
| 201 | +│ └── solid-oidc.js # DPoP verification |
| 202 | +├── wac/ |
| 203 | +│ ├── parser.js # ACL parsing |
| 204 | +│ └── checker.js # Permission checking |
| 205 | +├── ldp/ |
| 206 | +│ ├── headers.js # LDP Link headers |
| 207 | +│ └── container.js # Container JSON-LD |
| 208 | +├── webid/ |
| 209 | +│ └── profile.js # WebID generation |
| 210 | +├── patch/ |
| 211 | +│ └── n3-patch.js # N3 Patch support |
| 212 | +├── rdf/ |
| 213 | +│ ├── turtle.js # Turtle <-> JSON-LD |
| 214 | +│ └── conneg.js # Content negotiation |
| 215 | +└── utils/ |
| 216 | + └── url.js # URL utilities |
| 217 | +``` |
197 | 218 |
|
198 | | -### Customizing Benchmarks |
| 219 | +## Dependencies |
199 | 220 |
|
200 | | -You can customize the benchmark parameters in `benchmark.js`: |
| 221 | +Minimal dependencies for a fast, secure server: |
201 | 222 |
|
202 | | -- Concurrent users levels |
203 | | -- Operations per user |
204 | | -- Test duration |
205 | | -- Test user credentials |
| 223 | +- **fastify** - High-performance HTTP server |
| 224 | +- **fs-extra** - Enhanced file operations |
| 225 | +- **jose** - JWT/JWK handling for Solid-OIDC |
| 226 | +- **n3** - Turtle parsing (only used when conneg enabled) |
206 | 227 |
|
207 | | -## Contributing |
| 228 | +## License |
208 | 229 |
|
209 | | -Contributions are welcome! Please feel free to submit a Pull Request. |
| 230 | +MIT |
0 commit comments