Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"
104 changes: 104 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: CI
permissions:
contents: write
pull-requests: write
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version:
- 20.x
- 22.x
steps:
- uses: actions/checkout@v5
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build
- run: npm run test
- name: Save build
if: matrix.node-version == '20.x'
uses: actions/upload-artifact@v5
with:
name: build
path: |
.
!node_modules
retention-days: 1

gh-pages:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/download-artifact@v6
with:
name: build
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: .

dependabot:
name: 'Dependabot'
needs: build # After the E2E and build jobs, if one of them fails, it won't merge the PR.
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request'}} # Detect that the PR author is dependabot
steps:
- name: Enable auto-merge for Dependabot PRs
run: gh pr merge --auto --merge "$PR_URL" # Use Github CLI to merge automatically the PR
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

npm-publish-build:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v6
with:
name: build
- uses: actions/setup-node@v6
with:
node-version: 20.x
- uses: rlespinasse/github-slug-action@v3.x
- name: Append commit hash to package version
run: 'sed -i -E "s/(\"version\": *\"[^\"]+)/\1-${GITHUB_SHA_SHORT}/" package.json'
- name: Disable pre- and post-publish actions
run: 'sed -i -E "s/\"((pre|post)publish)/\"ignore:\1/" package.json'
- uses: JS-DevTools/npm-publish@v4.1.1
if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]'
with:
token: ${{ secrets.NPM_TOKEN }}
tag: ${{ env.GITHUB_REF_SLUG }}

npm-publish-latest:
needs: [build, npm-publish-build]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/download-artifact@v6
with:
name: build
- uses: actions/setup-node@v6
with:
node-version: 20.x
- name: Disable pre- and post-publish actions
run: 'sed -i -E "s/\"((pre|post)publish)/\"ignore:\1/" package.json'
- uses: JS-DevTools/npm-publish@v4.1.1
if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]'
with:
token: ${{ secrets.NPM_TOKEN }}
tag: latest
52 changes: 41 additions & 11 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function WsServer (server, opts) {
opts = opts || {}
this.suffix = opts.suffix || '.changes'
this.store = opts.store || new InMemory(opts)
this.authorize = opts.authorize // Authorization callback
var toChannel = opts.toChannel || defaultToChannel

// Starting WSS server
Expand All @@ -26,14 +27,20 @@ function WsServer (server, opts) {
})

// Handling a single connection
wss.on('connection', function (client) {
wss.on('connection', function (client, req) {
debug('New connection')
// var location = url.parse(client.upgradeReq.url, true)
// Store the request for authorization checks
client.upgradeReq = req

// Handling messages
client.on('message', function (message) {
debug('New message: ' + message)

// ws@8 may send Buffer, convert to string
if (Buffer.isBuffer(message)) {
message = message.toString()
}

if (!message || typeof message !== 'string') {
return
}
Expand All @@ -47,15 +54,38 @@ function WsServer (server, opts) {
return
}

var channel = toChannel ? toChannel(iri) : iri
self.store.subscribe(channel, iri, client, function (err, uuid) {
if (err) {
// TODO Should return an error
return
}

client.send('ack ' + tuple[1])
})
// Check authorization if callback is provided
if (self.authorize) {
self.authorize(iri, req, function (err, allowed) {
if (err || !allowed) {
debug('Subscription denied for ' + iri)
client.send('err ' + iri + ' forbidden')
return
}

// Authorization passed, proceed with subscription
var channel = toChannel ? toChannel(iri) : iri
self.store.subscribe(channel, iri, client, function (err, uuid) {
if (err) {
client.send('err ' + iri + ' error')
return
}

client.send('ack ' + tuple[1])
})
})
} else {
// No authorization, proceed directly
var channel = toChannel ? toChannel(iri) : iri
self.store.subscribe(channel, iri, client, function (err, uuid) {
if (err) {
// TODO Should return an error
return
}

client.send('ack ' + tuple[1])
})
}
})

// Respond to ping
Expand Down
Loading