Skip to content

Commit fd5837c

Browse files
authored
Merge pull request #1797 from nodeSolidServer/basic-prep
Basic prep
2 parents f5b2b5c + 29f3e08 commit fd5837c

24 files changed

+1409
-893
lines changed

.github/workflows/ci.yml

+18-5
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,30 @@ jobs:
1717

1818
strategy:
1919
matrix:
20-
node-version: [18.x]
20+
node-version: [ '>=20.17.0' ]
2121
os: [ubuntu-latest]
2222

2323
steps:
24-
- uses: actions/checkout@v2
24+
- uses: actions/checkout@v4
25+
26+
# extract repository name
27+
- if: github.event_name == 'pull_request'
28+
run: echo "REPO_NAME=${{ github.event.pull_request.head.repo.full_name }}" >> $GITHUB_ENV
29+
30+
- if: github.event_name != 'pull_request'
31+
run: echo "REPO_NAME=${GITHUB_REPOSITORY}" >> $GITHUB_ENV
32+
2533
# extract branch name
2634
- if: github.event_name == 'pull_request'
2735
run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
36+
2837
- if: github.event_name != 'pull_request'
2938
run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
3039

40+
# print repository name
41+
- name: Get repository name
42+
run: echo 'The repository name is' $REPO_NAME
43+
3144
# print branch name
3245
- name: Get branch name
3346
run: echo 'The branch name is' $BRANCH_NAME
@@ -40,12 +53,12 @@ jobs:
4053
# test code
4154
- run: npm run standard
4255
- run: npm run validate
43-
- run: npm run nyc
56+
- run: npm run c8
4457
# Test global install of the package
4558
- run: npm pack .
4659
- run: npm install -g solid-server-*.tgz
4760
# Run the Solid test-suite
48-
- run: bash test/surface/run-solid-test-suite.sh $BRANCH_NAME
61+
- run: bash test/surface/run-solid-test-suite.sh $BRANCH_NAME $REPO_NAME
4962

5063
# TODO: The pipeline should automate publication to npm, so that the docker build gets the correct version
5164
# This job will only dockerize solid-server@latest / solid-server@<tag-name> from npmjs.com!
@@ -56,7 +69,7 @@ jobs:
5669
runs-on: ubuntu-latest
5770
steps:
5871

59-
- uses: actions/checkout@v2
72+
- uses: actions/checkout@v4
6073

6174
- uses: olegtarasov/[email protected]
6275
id: tagName

README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Your users will have a dedicated folder under `./data` at `./data/<username>.<yo
138138
> To use Gmail you may need to configure ["Allow Less Secure Apps"](https://www.google.com/settings/security/lesssecureapps) in your Gmail account unless you are using 2FA in which case you would have to create an [Application Specific](https://security.google.com/settings/security/apppasswords) password. You also may need to unlock your account with ["Allow access to your Google account"](https://accounts.google.com/DisplayUnlockCaptcha) to use SMTP.
139139
140140
also add to `config.json`
141-
```
141+
```
142142
"useEmail": true,
143143
"emailHost": "smtp.gmail.com",
144144
"emailPort": "465",
@@ -206,6 +206,7 @@ $ solid start --help
206206
--multiuser Enable multi-user mode
207207
--idp [value] Obsolete; use --multiuser
208208
--no-live Disable live support through WebSockets
209+
--no-prep Disable Per Resource Events
209210
--proxy [value] Obsolete; use --corsProxy
210211
--cors-proxy [value] Serve the CORS proxy on this path
211212
--suppress-data-browser Suppress provision of a data browser
@@ -271,7 +272,7 @@ docker run -p 8443:8443 --name solid node-solid-server
271272

272273

273274
This will enable you to login to solid on https://localhost:8443 and then create a new account
274-
but not yet use that account. After a new account is made you will need to create an entry for
275+
but not yet use that account. After a new account is made you will need to create an entry for
275276
it in your local (/etc/)hosts file in line with the account and subdomain, i.e. --
276277

277278
```pre
@@ -280,16 +281,16 @@ it in your local (/etc/)hosts file in line with the account and subdomain, i.e.
280281

281282
You can modify the config within the docker container as follows:
282283

283-
- Copy the `config.json` to the current directory with:
284+
- Copy the `config.json` to the current directory with:
284285
```bash
285286
docker cp solid:/usr/src/app/config.json .
286287
```
287288
- Edit the `config.json` file
288-
- Copy the file back with
289+
- Copy the file back with
289290
```bash
290291
docker cp config.json solid:/usr/src/app/
291292
```
292-
- Restart the server with
293+
- Restart the server with
293294
```bash
294295
docker restart solid
295296
```

bin/lib/options.js

+6
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,12 @@ module.exports = [
143143
flag: true,
144144
default: false
145145
},
146+
{
147+
name: 'no-prep',
148+
help: 'Disable Per Resource Events',
149+
flag: true,
150+
default: false
151+
},
146152
// {
147153
// full: 'default-app',
148154
// help: 'URI to use as a default app for resources (default: https://linkeddata.github.io/warp/#/list/)'

bin/solid

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
#!/usr/bin/env node
1+
#!/usr/bin/env -S node --experimental-require-module
22
const startCli = require('./lib/cli')
33
startCli()

bin/solid.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
#!/usr/bin/env node
1+
#!/usr/bin/env -S node --experimental-require-module
22
const startCli = require('./lib/cli')
33
startCli()

docker-image/src/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:16-alpine
1+
FROM node:20-alpine
22

33
# hadolint ignore=DL3018
44
RUN apk add --no-cache openssl

lib/create-app.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ const ResourceMapper = require('./resource-mapper')
2828
const aclCheck = require('@solid/acl-check')
2929
const { version } = require('../package.json')
3030

31+
const acceptEvents = require('express-accept-events').default
32+
const events = require('express-negotiate-events').default
33+
const eventID = require('express-prep/event-id').default
34+
const prep = require('express-prep').default
35+
3136
const corsSettings = cors({
3237
methods: [
3338
'OPTIONS', 'HEAD', 'GET', 'PATCH', 'POST', 'PUT', 'DELETE'
@@ -61,6 +66,12 @@ function createApp (argv = {}) {
6166

6267
const app = express()
6368

69+
// Add PREP support
70+
if (argv.prep) {
71+
app.use(eventID)
72+
app.use(acceptEvents, events, prep)
73+
}
74+
6475
initAppLocals(app, argv, ldp)
6576
initHeaders(app)
6677
initViews(app, configPath)
@@ -115,7 +126,7 @@ function createApp (argv = {}) {
115126
}
116127

117128
// Attach the LDP middleware
118-
app.use('/', LdpMiddleware(corsSettings))
129+
app.use('/', LdpMiddleware(corsSettings, argv.prep))
119130

120131
// https://stackoverflow.com/questions/51741383/nodejs-express-return-405-for-un-supported-method
121132
app.use(function (req, res, next) {
@@ -168,6 +179,7 @@ function initAppLocals (app, argv, ldp) {
168179
app.locals.enforceToc = argv.enforceToc
169180
app.locals.tocUri = argv.tocUri
170181
app.locals.disablePasswordChecks = argv.disablePasswordChecks
182+
app.locals.prep = argv.prep
171183

172184
if (argv.email && argv.email.host) {
173185
app.locals.emailService = new EmailService(argv.templates.email, argv.email)
@@ -287,7 +299,7 @@ function initWebId (argv, app, ldp) {
287299
initAuthentication(app, argv)
288300

289301
if (argv.multiuser) {
290-
app.use(vhost('*', LdpMiddleware(corsSettings)))
302+
app.use(vhost('*', LdpMiddleware(corsSettings, argv.prep)))
291303
}
292304
}
293305

lib/debug.js

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ exports.accounts = debug('solid:accounts')
1515
exports.email = debug('solid:email')
1616
exports.ldp = debug('solid:ldp')
1717
exports.fs = debug('solid:fs')
18+
exports.prep = debug('solid:prep')

lib/handlers/delete.js

+3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ async function handler (req, res, next) {
66
debug('DELETE -- Request on' + req.originalUrl)
77

88
const ldp = req.app.locals.ldp
9+
const prep = req.app.locals.prep
910
try {
1011
await ldp.delete(req)
1112
debug('DELETE -- Ok.')
13+
// Add event-id for notifications
14+
prep && res.setHeader('Event-ID', res.setEventID())
1215
res.sendStatus(200)
1316
next()
1417
} catch (err) {

lib/handlers/get.js

+32-7
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@ const translate = require('../utils.js').translate
1717
const error = require('../http-error')
1818

1919
const RDFs = require('../ldp').mimeTypesAsArray()
20+
const isRdf = require('../ldp').mimeTypeIsRdf
21+
22+
const prepConfig = 'accept=("message/rfc822" "application/ld+json" "text/turtle")'
2023

2124
async function handler (req, res, next) {
2225
const ldp = req.app.locals.ldp
26+
const prep = req.app.locals.prep
2327
const includeBody = req.method === 'GET'
2428
const negotiator = new Negotiator(req)
2529
const baseUri = ldp.resourceMapper.resolveUrl(req.hostname, req.path)
@@ -103,22 +107,35 @@ async function handler (req, res, next) {
103107
debug(' sending data browser file: ' + dataBrowserPath)
104108
res.sendFile(dataBrowserPath)
105109
return
106-
} else if (stream) {
110+
} else if (stream) { // EXIT text/html
107111
res.setHeader('Content-Type', contentType)
108112
return stream.pipe(res)
109113
}
110114
}
111115

112116
// If request accepts the content-type we found
113117
if (stream && negotiator.mediaType([contentType])) {
114-
res.setHeader('Content-Type', contentType)
118+
let headers = {
119+
'Content-Type': contentType
120+
}
115121
if (contentRange) {
116-
const headers = { 'Content-Range': contentRange, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize }
117-
res.writeHead(206, headers)
118-
return stream.pipe(res)
119-
} else {
120-
return stream.pipe(res)
122+
headers = {
123+
...headers,
124+
'Content-Range': contentRange,
125+
'Accept-Ranges': 'bytes',
126+
'Content-Length': chunksize
127+
}
128+
res.statusCode = 206
121129
}
130+
131+
if (prep & isRdf(contentType) && !res.sendEvents({
132+
config: { prep: prepConfig },
133+
body: stream,
134+
isBodyStream: true,
135+
headers
136+
})) return
137+
res.set(headers)
138+
return stream.pipe(res)
122139
}
123140

124141
// If it is not in our RDFs we can't even translate,
@@ -130,6 +147,14 @@ async function handler (req, res, next) {
130147
// Translate from the contentType found to the possibleRDFType desired
131148
const data = await translate(stream, baseUri, contentType, possibleRDFType)
132149
debug(req.originalUrl + ' translating ' + contentType + ' -> ' + possibleRDFType)
150+
const headers = {
151+
'Content-Type': possibleRDFType
152+
}
153+
if (prep && isRdf(contentType) && !res.sendEvents({
154+
config: { prep: prepConfig },
155+
body: data,
156+
headers
157+
})) return
133158
res.setHeader('Content-Type', possibleRDFType)
134159
res.send(data)
135160
return next()

0 commit comments

Comments
 (0)