Showing preview only (1,100K chars total). Download the full file or copy to clipboard to get everything.
Repository: deepstreamIO/deepstream.io
Branch: master
Commit: e789afa7497b
Files: 254
Total size: 1.0 MB
Directory structure:
gitextract_5br62wbj/
├── .dockerignore
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.md
│ └── workflows/
│ ├── lint-test.yml
│ └── release.yml
├── .gitignore
├── .gitmodules
├── .npmignore
├── CHANGELOG.md
├── Dockerfile
├── Dockerfile.alpine
├── LICENSE
├── README.md
├── SECURITY.md
├── ascii-logo.txt
├── bin/
│ ├── deepstream-cluster.ts
│ ├── deepstream-daemon.ts
│ ├── deepstream-hash.ts
│ ├── deepstream-info.ts
│ ├── deepstream-nginx.ts
│ ├── deepstream-service.ts
│ ├── deepstream-start.ts
│ └── deepstream.ts
├── conf/
│ ├── config.yml
│ ├── permissions.yml
│ └── users.yml
├── package.json
├── scripts/
│ ├── connector/
│ │ ├── package-connector.sh
│ │ └── test-connector.sh
│ ├── details.js
│ ├── executable-test.js
│ ├── license-aggregator.js
│ ├── linux-package.sh
│ ├── linux-test.sh
│ ├── node-test.js
│ ├── package.sh
│ ├── pkg.js
│ ├── release.sh
│ ├── resources/
│ │ ├── PackageInfo
│ │ ├── daemon/
│ │ │ ├── after-install
│ │ │ ├── after-upgrade
│ │ │ ├── before-remove
│ │ │ └── before-upgrade
│ │ ├── missing-licenses.txt
│ │ └── node.rc
│ ├── sanity-test.sh
│ ├── setup.sh
│ ├── trigger-build.sh
│ └── tsc.sh
├── src/
│ ├── config/
│ │ ├── config-initialiser.spec.ts
│ │ ├── config-initialiser.ts
│ │ ├── config-validator.ts
│ │ ├── ds-info.ts
│ │ ├── file-utils.spec.ts
│ │ ├── file-utils.ts
│ │ ├── js-yaml-loader.spec.ts
│ │ └── js-yaml-loader.ts
│ ├── connection-endpoint/
│ │ ├── base/
│ │ │ ├── connection-endpoint.spec.ts
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper.ts
│ │ ├── http/
│ │ │ ├── connection-endpoint.spec.ts
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper.ts
│ │ ├── mqtt/
│ │ │ ├── connection-endpoint.ts
│ │ │ ├── message-parser.ts
│ │ │ └── socket-wrapper-factory.ts
│ │ └── websocket/
│ │ ├── binary/
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper-factory.ts
│ │ ├── json/
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper-factory.ts
│ │ └── text/
│ │ ├── connection-endpoint.ts
│ │ ├── socket-wrapper-factory.ts
│ │ └── text-protocol/
│ │ ├── constants.ts
│ │ ├── message-builder.ts
│ │ ├── message-parser.ts
│ │ └── utils.ts
│ ├── constants.ts
│ ├── deepstream.io.spec.ts
│ ├── deepstream.io.ts
│ ├── default-options.ts
│ ├── handlers/
│ │ ├── event/
│ │ │ ├── event-handler.spec.ts
│ │ │ └── event-handler.ts
│ │ ├── monitoring/
│ │ │ └── monitoring.ts
│ │ ├── presence/
│ │ │ ├── presence-handler.spec.ts
│ │ │ └── presence-handler.ts
│ │ ├── record/
│ │ │ ├── record-deletion.spec.ts
│ │ │ ├── record-deletion.ts
│ │ │ ├── record-handler-permission.spec.ts
│ │ │ ├── record-handler.spec.ts
│ │ │ ├── record-handler.ts
│ │ │ ├── record-request.spec.ts
│ │ │ ├── record-request.ts
│ │ │ ├── record-transition.spec.ts
│ │ │ ├── record-transition.ts
│ │ │ ├── record-write-acknowledgement.spec.ts
│ │ │ └── test-messages.ts
│ │ └── rpc/
│ │ ├── rpc-handler.spec.ts
│ │ ├── rpc-handler.ts
│ │ ├── rpc-proxy.spec.ts
│ │ ├── rpc-proxy.ts
│ │ └── rpc.ts
│ ├── jif/
│ │ ├── jif-handler.spec.ts
│ │ ├── jif-handler.ts
│ │ └── jif-schema.ts
│ ├── listen/
│ │ ├── listener-registry.spec.ts
│ │ ├── listener-registry.ts
│ │ └── listener-test-utils.ts
│ ├── plugins/
│ │ └── heap-snapshot/
│ │ └── heap-snapshot.ts
│ ├── service/
│ │ ├── daemon.ts
│ │ ├── service.ts
│ │ └── template/
│ │ ├── initd.ts
│ │ └── systemd.ts
│ ├── services/
│ │ ├── authentication/
│ │ │ ├── combine/
│ │ │ │ └── combine-authentication.ts
│ │ │ ├── file/
│ │ │ │ ├── file-based-authentication.spec.ts
│ │ │ │ └── file-based-authentication.ts
│ │ │ ├── http/
│ │ │ │ ├── http-authentication.spec.ts
│ │ │ │ └── http-authentication.ts
│ │ │ ├── open/
│ │ │ │ ├── open-authentication.spec.ts
│ │ │ │ └── open-authentication.ts
│ │ │ └── storage/
│ │ │ └── storage-based-authentication.ts
│ │ ├── cache/
│ │ │ ├── local-cache.spec.ts
│ │ │ └── local-cache.ts
│ │ ├── cluster-node/
│ │ │ ├── single-cluster-node.ts
│ │ │ └── vertical-cluster-node.ts
│ │ ├── cluster-registry/
│ │ │ ├── distributed-cluster-registry.ts
│ │ │ └── distributed-state-registry-factory.ts
│ │ ├── cluster-state/
│ │ │ ├── distributed-state-registry-factory.ts
│ │ │ ├── distributed-state-registry.ts
│ │ │ └── single-state-registry.ts
│ │ ├── http/
│ │ │ ├── node/
│ │ │ │ └── node-http.ts
│ │ │ └── uws/
│ │ │ └── uws-http.ts
│ │ ├── lock/
│ │ │ └── distributed-lock-registry.ts
│ │ ├── logger/
│ │ │ ├── pino/
│ │ │ │ └── pino-logger.ts
│ │ │ └── std/
│ │ │ ├── std-out-logger.spec.ts
│ │ │ └── std-out-logger.ts
│ │ ├── monitoring/
│ │ │ ├── combine-monitoring.ts
│ │ │ ├── http/
│ │ │ │ ├── monitoring-http.spec.ts
│ │ │ │ └── monitoring-http.ts
│ │ │ ├── log/
│ │ │ │ ├── monitoring-log.spec.ts
│ │ │ │ └── monitoring-log.ts
│ │ │ ├── monitoring-base.ts
│ │ │ └── noop-monitoring.ts
│ │ ├── permission/
│ │ │ ├── open/
│ │ │ │ ├── open-permission.spec.ts
│ │ │ │ └── open-permission.ts
│ │ │ └── valve/
│ │ │ ├── config-compiler.spec.ts
│ │ │ ├── config-compiler.ts
│ │ │ ├── config-permission-basic.spec.ts
│ │ │ ├── config-permission-create.spec.ts
│ │ │ ├── config-permission-cross-reference.spec.ts
│ │ │ ├── config-permission-load.spec.ts
│ │ │ ├── config-permission-nested-cross-reference.spec.ts
│ │ │ ├── config-permission-other.spec.ts
│ │ │ ├── config-permission-record-patch.spec.ts
│ │ │ ├── config-permission.ts
│ │ │ ├── config-schema.ts
│ │ │ ├── config-validator.spec.ts
│ │ │ ├── config-validator.ts
│ │ │ ├── path-parser.spec.ts
│ │ │ ├── path-parser.ts
│ │ │ ├── rule-application.ts
│ │ │ ├── rule-cache.spec.ts
│ │ │ ├── rule-cache.ts
│ │ │ ├── rule-parser.spec.ts
│ │ │ ├── rule-parser.ts
│ │ │ ├── rules-map.spec.ts
│ │ │ └── rules-map.ts
│ │ ├── storage/
│ │ │ ├── noop-storage.spec.ts
│ │ │ └── noop-storage.ts
│ │ ├── subscription-registry/
│ │ │ ├── default-subscription-registry-factory.ts
│ │ │ ├── default-subscription-registry.spec.ts
│ │ │ └── default-subscription-registry.ts
│ │ └── telemetry/
│ │ └── deepstreamio-telemetry.ts
│ ├── test/
│ │ ├── common.ts
│ │ ├── config/
│ │ │ ├── basic-permission-config.json
│ │ │ ├── basic-valid-json.json
│ │ │ ├── blank-config.json
│ │ │ ├── config-broken.js
│ │ │ ├── config-broken.yml
│ │ │ ├── config.js
│ │ │ ├── config.yml
│ │ │ ├── empty-map-config.json
│ │ │ ├── exists-test/
│ │ │ │ ├── a-file.js
│ │ │ │ ├── a-file.yml
│ │ │ │ └── a-json-file.json
│ │ │ ├── invalid-permission-conf.json
│ │ │ ├── invalid-user-config.json
│ │ │ ├── json-with-env-variables.json
│ │ │ ├── no-private-events-permission-config.json
│ │ │ ├── sslKey.pem
│ │ │ ├── users-unhashed.json
│ │ │ └── users.json
│ │ ├── helper/
│ │ │ ├── start-test-server.ts
│ │ │ ├── test-helper.ts
│ │ │ ├── test-http-server.ts
│ │ │ └── test-mocks.ts
│ │ └── mock/
│ │ ├── authentication-handler-mock.ts
│ │ ├── http-mock.ts
│ │ ├── logger-mock.ts
│ │ ├── message-connector-mock.ts
│ │ ├── permission-handler-mock.ts
│ │ ├── plugin-mock.ts
│ │ ├── socket-mock.ts
│ │ ├── socket-wrapper-factory-mock.ts
│ │ └── storage-mock.ts
│ └── utils/
│ ├── dependency-initialiser.spec.ts
│ ├── dependency-initialiser.ts
│ ├── json-path.spec.ts
│ ├── json-path.ts
│ ├── message-distributor.spec.ts
│ ├── message-distributor.ts
│ ├── message-processor.spec.ts
│ ├── message-processor.ts
│ ├── utils.spec.ts
│ └── utils.ts
├── telemetry-server/
│ ├── package.json
│ ├── telemetry-server.config.js
│ └── telemetry-server.ts
├── test-e2e/
│ ├── config/
│ │ ├── permissions-complex.json
│ │ └── permissions-open.json
│ ├── framework/
│ │ ├── client-handler.ts
│ │ ├── client.ts
│ │ ├── event.ts
│ │ ├── listening.ts
│ │ ├── presence.ts
│ │ ├── record.ts
│ │ ├── rpc.ts
│ │ ├── utils.ts
│ │ └── world.ts
│ ├── framework-v3/
│ │ ├── client-handler.ts
│ │ ├── client.ts
│ │ ├── event.ts
│ │ ├── listening.ts
│ │ ├── presence.ts
│ │ ├── record.ts
│ │ ├── rpc.ts
│ │ ├── utils.ts
│ │ └── world.ts
│ ├── steps/
│ │ ├── client/
│ │ │ ├── client-definition-step.ts
│ │ │ ├── connection-steps.ts
│ │ │ ├── event-steps.ts
│ │ │ ├── listening-steps.ts
│ │ │ ├── presence-steps.ts
│ │ │ ├── record-steps.ts
│ │ │ └── rpc-steps.ts
│ │ ├── http/
│ │ │ └── http-steps.ts
│ │ └── server/
│ │ └── step-definition-server.ts
│ └── tools/
│ ├── e2e-authentication.ts
│ ├── e2e-cluster-node.ts
│ ├── e2e-harness.ts
│ ├── e2e-logger.ts
│ └── e2e-server-config.ts
├── tsconfig.json
├── tslint.json
└── types/
├── global.d.ts
└── uws.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
**/.git/
**/.github/
**/node_modules/
**/Dockerfile
**/Dockerfile.*
**/.env.*.local
**/.env.local
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Server version**
**Protocol (binary or text)**
**Websocket server (node-http or uws)**
**Server OS**
**Node version**
**Server config**
Please share the config sections that might be relevant for this issue
**Client (Js, Java, other) and client version**
**Client config**
Please share the config sections that might be relevant for this issue
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/workflows/lint-test.yml
================================================
name: lint-and-test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: '22.x'
- run: npm install
- run: npm run lint
- run: npm run test:all:coverage
- run: npm run e2e:uws
- name: Coveralls
if: startsWith(matrix.node-version, '22.')
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
create_release:
name: Create release
runs-on: ubuntu-latest
steps:
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
npm_publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v3
with:
node-version: '22.x'
registry-url: 'https://registry.npmjs.org'
- run: npm install
- run: npm run lint
- run: npm run test
- run: npm run tsc
- run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
linux:
runs-on: ubuntu-latest
steps:
- name: Checkout reposistory
uses: actions/checkout@v3
- name: Checkout submodules
run: git submodule update --init --recursive
- name: Use Node.js
env:
DEFAULT_DELAY: 50
uses: actions/setup-node@v3
with:
node-version: '22.x'
- run: npm install
- run: npm run lint
- run: npm run test
- run: bash ./scripts/package.sh true true
- name: Upload Release Asset
uses: alexellis/upload-assets@0.2.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
asset_paths: '["build/*/*.tar.gz"]'
windows:
runs-on: windows-latest
steps:
- name: Checkout reposistory
uses: actions/checkout@v3
- name: Checkout submodules
run: git submodule update --init --recursive
- name: Use Node.js
env:
DEFAULT_DELAY: 50
uses: actions/setup-node@v3
with:
node-version: '22.x'
- run: npm install
- run: npm run lint
- run: npm run test
- run: bash ./scripts/package.sh true true
- name: Upload Release Asset
uses: alexellis/upload-assets@0.2.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
asset_paths: '["build/*/*.zip"]'
macos:
runs-on: macos-latest
steps:
- name: Checkout reposistory
uses: actions/checkout@v3
- name: Checkout submodules
run: git submodule update --init --recursive
- name: Use Node.js
env:
DEFAULT_DELAY: 50
uses: actions/setup-node@v3
with:
node-version: '22.x'
- run: npm install
- run: npm run lint
- run: npm run test
- run: bash ./scripts/package.sh true true
- name: Upload Release Asset
uses: alexellis/upload-assets@0.2.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
asset_paths: '["build/*/*.pkg"]'
docker-amd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: deepstreamio/deepstream.io
flavor: |
latest=true
tags: |
type=semver,pattern={{version}}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile
push: true
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-arm:
runs-on: ubuntu-latest
steps:
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- uses: actions/checkout@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: deepstreamio/deepstream.io
flavor: |
latest=true
tags: |
type=semver,pattern={{version}}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile
push: true
platforms: linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-alpine:
runs-on: ubuntu-latest
steps:
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
- uses: actions/checkout@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: deepstreamio/deepstream.io
flavor: |
latest=true
suffix=-alpine,onlatest=true
tags: |
type=semver,pattern={{version}}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile.alpine
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
================================================
FILE: .gitignore
================================================
heap-snapshots
.nyc_combined_coverage
dist
.DS_Store
.vscode/settings.json
.nyc_output
temp-e2e-test
local-storage
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# pkg
build
meta.json
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules
npm-shrinkwrap.json
npm-debug.*
# Users Environment Variables
.lock-wscript
# IDE configuration
.idea
licenses.json
# Typescript
dist
================================================
FILE: .gitmodules
================================================
[submodule "test-e2e/features"]
path = test-e2e/features
url = https://github.com/deepstreamIO/deepstream.io-e2e.git
[submodule "connectors/cache/redis"]
path = connectors/cache/redis
url = https://github.com/deepstreamIO/deepstream.io-cache-redis.git
[submodule "connectors/cache/memcached"]
path = connectors/cache/memcached
url = https://github.com/deepstreamIO/deepstream.io-cache-memcached.git
[submodule "connectors/cache/hazelcast"]
path = connectors/cache/hazelcast
url = https://github.com/deepstreamIO/deepstream.io-cache-hazelcast.git
[submodule "connectors/storage/postgres"]
path = connectors/storage/postgres
url = https://github.com/deepstreamIO/deepstream.io-storage-postgres.git
[submodule "connectors/storage/rethinkdb"]
path = connectors/storage/rethinkdb
url = https://github.com/deepstreamIO/deepstream.io-storage-rethinkdb.git
[submodule "connectors/storage/mongodb"]
path = connectors/storage/mongodb
url = https://github.com/deepstreamIO/deepstream.io-storage-mongodb.git
[submodule "connectors/storage/elasticsearch"]
path = connectors/storage/elasticsearch
url = https://github.com/deepstreamIO/deepstream.io-storage-elasticsearch.git
[submodule "client"]
path = client
url = https://github.com/deepstreamIO/deepstream.io-client-js.git
[submodule "connectors/clusterNode/redis"]
path = connectors/clusterNode/redis
url = https://github.com/deepstreamIO/deepstream.io-clusternode-redis.git
[submodule "connectors/logger/winston"]
path = connectors/logger/winston
url = https://github.com/deepstreamIO/deepstream.io-logger-winston.git
[submodule "plugins/aws"]
path = plugins/aws
url = https://github.com/deepstreamIO/deepstream.io-plugin-aws.git
================================================
FILE: .npmignore
================================================
# Typescript files
/scripts
/bin
.tsconfig.json
.tslint.json
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# pkg
build
meta.json
# Users Environment Variables
.lock-wscript
# IDE configuration
.idea
# CI
.travis.yml
appveyor.yml
# testing
test
test-e2e
benchmarks
================================================
FILE: CHANGELOG.md
================================================
## [10.0.0] - 2025.08.02
### Fix - BREAKING CHANGE
The storage authentication service, when creating new users automatically, was encoding the password hashes in 'ascii' format which can create characters that are not allowed in a database text field. This has been fixed by encoding the password hashes in 'base64'. Since this is a crippling bug and no one noticed before, I'm going to assume the feature is not being used in production and therefore a new non-backwards compatible version will be released.
### Chore
## [9.1.3] - 2025.07.04
### Fix
Handle Erase messages as Delete messages in valve permissions
## [9.1.2] - 2025.06.30
### Fix
Log metadata
## [9.1.1] - 2025.06.18
### Fix - lint
## [9.1.0] - 2025.06.18
### Fix - breaking change
when using uws http server response.writeStatus must be called before any other method, otherwise all response status are 200.
I decided not to make a major release because if somebody else was using it a bug report would have been made.
And thanks to a LLM's for the quick refactoring!
## [9.0.1] - 2025.06.17
### Feature
Enable pino logger options thus making it possible to use transports
## [9.0.0] - 2025.06.13
### Fix - Breaking change
- The log level namig logic was not being implemented properly. logLevels as String where not converted to numbers, therefore those levels where not being properly enforced. The simplest path is just to use logLevels as numbers everywhere. This is a breaking change because config files with log levels as string will error at the config validation stage.
### Chore
- Update deps
## [8.0.0] - 2025.04.26
### Chore
- Update nodejs to version 22.x
- Update uWebsockets
- Update deps
## [7.0.10] - 2024.03.06
### Task
- Separate docker ubuntu amd and arm releases due to intermitent build failures in arm. See https://github.com/nodejs/docker-node/issues/1335
## [7.0.9] - 2024.03.04
### Fix
- http auth issue #1138
## [7.0.8] - 2023.10.23
### Task
- multi arch docker image builds. Thanks @daanh432
### Chore
- update deps. Thanks @hugojosefson
## [7.0.7] - 2023.07.20
### Fix
- Cork uWebsocketjs http responses
## [7.0.6] - 2023.07.19
### Task
- update uWebsocketjs
## [7.0.5] - 2023.03.24
### Fix
- use cli/config file options for cluster
## [7.0.4] - 2023.03.08
### Feature
- deepstream cluster CLI enabled in order to run a cluster of deepstream servers on each available processor core
- combine monitoring: now deepstream accepts an array of monitoring plugins in order to have separate plugins when it comes to monitoring messages, server activity and other custom functionality that might be required. For example you can run the included log monitoring, and an audit plugin that could save to another system/server which users are writing to which records by listening to incoming messages. This allows to create inmediate database replication strategies and so forth.
## [7.0.3] - 2023.03.02
### Fix
- set pkg entrypoint for daemon
## [7.0.2] - 2023.02.27
### Fix
- log monitoring
- daemon issues due to pkg bug
## [7.0.1] - 2023.02.03
### Fix
- pkg issues
## [7.0.0] - 2023.02.03
### Chore
- Update nodejs to version 18.x
- Update uWebsockets
- Update deps
## [6.2.2] - 2022.12.22
### Fix
- Enforce http origins options
- log a warning when a websocket message is not sent
- uws server add maxBackpressure option, defaults to 1024*1024
## [6.2.1] - 2022.06.20
### Task
- update deps
## [6.2.0] - 2022.06.05
### Task
- eliminate externalUrl from config and cluster messages since it was not used
- set `provideRequestorName` and `provideRequestorData` as false by default to avoid overhead since from now on that data can actually be sent on rpc messages and handled on @deepstream/client > 6.0.2.
### Misc
- update submodules and deps
## [6.1.2] - 2022.04.22
### Fix
- Revert to lockfileVersion 1
## [6.1.1] - 2022.04.22
### Fix
- Check maxMessageSize limit on POST requests when using uws http server
### Chore
- update @deepstream/client dev dependency and update e2e tests
## [6.1.0] - 2022.03.17
### Fix
- Send write ack error messages when cache, storage or permission fails. For this to work it requires client version >= 6
- Do not remove cluster nodes if cluster size is 1
### Feature
- Enable vertical cluster node option:
Now we can use all available cores in a vertical cluster! By setting the cluster option to `clusterNode: { name: 'vertical' }` you can run as many deepstream instances you want in each of the server cores and it will be one syncronized cluster.
## [6.0.1] - 2022.01.02
### Task
- Check that executable works in pre-push hook
- Use pkg instead of nexe
## [6.0.0] - 2021.12.12
### Chore
- Update nodejs to version 14.x
- Update uWebsockets
## [5.2.6] - 2021.11.27
### Misc
- Update dependencies
## [5.2.5] - 2021.11.27
### Misc
- Update dependencies
## [5.2.4] - 2021.04.05
### Misc
- Disable telemetry
## [5.2.3] - 2021.03.09
### Feature
- enable combine authentication. Now when the auth config has more than one authentication strategy the server will query them in order untill one passes or all fail.
## [5.2.2] - 2021.03.01
### Feature
- enable querying for specific user presence on http endpoint
## [5.2.1] - 2021.02.24
### Fixes
- uws idleTimeout is in seconds! That's why it didn't closed the connection on time.
- buffer ack messages
- remove noDelay from default-options and use it on subscription registry as a param to enable/disable buffering
## [5.2.0] - 2021.02.17
### Task
- Github Actions CI/CD
## [5.1.8] - 2020.11.25
### Misc
- Updating uws to support apple silicon
### Fix
- Increasing CI heartbeat timeouts
## [5.1.7] - 2020.11.25
### Fix
- Calling destroy on socketWrapper instead of close, since close is a reaction and destroy an action
## [5.1.6] - 2020.11.24
### Fix
- Fix #1091 heartbeat not working with node-http/ws
This fix now adds a timestamps to every message frame recieved and sets up an interval
per socket to check heartbeat exists. Didn't do any performance tests but I'm assuming having a single interval is cheaper than setting a timeout and canceling on each message.
This fix also exposes that we don't serialize STATE_TOPIC_REGISTRY/NOT_SUBSCRIBED message correctly which throws an error and crashes the server. That fix will require more elbow grease and hasn't been reported so will just keep an eye on issues.
## [5.1.5] - 2020.10.29
### Fix
- Fix #1089 install service gives error
### Misc
- Updating dependencies
## [5.1.4] - 2020.10.16
### Fix
- Fixed bug causing the server to crash with older sdks.
## [5.1.3] - 2020.08.08
### Fix
- Use upgrade property for uWebSockets http server.
### Misc
- Do not run e2e:v3 test on the pre-push hook
## [5.1.2] - 2020.07.05
### Misc
- Updating all dependencies
## [5.1.1] - 2020.05.11
### Fix
Disabling telemetry for tests
Fixing critical bug with client sdk version tracking
## [5.1.0] - 2020.05.11
### Feat
Adding telemetry. The server code is also in the rep (under telemetry-server).
This uses a random uuid as your deploymentId, which is pretty much the only way
I can avoid having thousands of records in the database from one machine restarting / ci process.
If possible please use a different ID for production environments!
```yaml
# This disables specific feature in DS, which is a more performant way
# than disabling via permissions and is also how telemetry figures out
# what features are enabled
enabledFeatures:
record: true
event: true
rpc: true
presence: true
telemetry:
type: deepstreamIO
options:
# Disable telemetry entirely
enabled: true
# Prints whatever will be sent to the telemetry endpoint,
# without actually sending it
debug: false
# An anonymous uuid that allows us to know its one unique
# deployment. Please don't generate these randomly, it really
# skews up analytics. This is in the config and user generated
# because we don't want to
deploymentId: <uuid goes here>
```
### Fix
Fixes by the awesome @jaime-ez around heartbeats and ping messages!
## [5.0.16] - 2020.04.30
### Feat
- Add two new plugins:
- heap-snapshot
This allows deepstream to save its heap space for analysis by v8 tools
```yaml
plugins:
heap-snapshot:
name: 'heap-snapshot'
options:
interval: 60000
outputDir: file(../heap-snapshots)
```
- aws
This is a general plugin for all AWS services, currently allows us to sync
the heap-snapshot directory to S3 which is useful when running via docker.
The functionality however is generic, so you could have a plugin that outputs
other useful data.
You can also very simply add more services (or more of the same ones). This
just makes it easier for us to maintain the plugin.
```yaml
plugins:
aws:
name: aws
options:
accessKeyId: ${AWS_ACCESS_KEY}
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
services:
- type: s3-sync
options:
syncInterval: 60000
syncDir: file(../heap-snapshots)
bucketName: ${SYNC_BUCKET_NAME}
bucketRegion: ${AWS_DEFAULT_REGION}
```
- SocketData is passed to monitoring service in order to allow for fined grain monitoring.
### Fix
- uws service accepts options requests and enforces CORS params
## [5.0.15] - 2020.04.24
### Fix
- Allowing valve file to be passed in via nodeJS config (@jaime-ez)
### Misc
- Updating uws dependency
## [5.0.14] - 2020.04.19
### Misc
- Adding a log line for MQTT incoming connections for clarity
## [5.0.13] - 2020.04.16
### Fix
- Fixing issue where record updates via clusters didn't always get sent correctly to subscribers
### Misc
- Updating dependencies
## [5.0.12] - 2020.03.06
### Fix
- Fixing issue where sending messages between multiple protocols can break. Verbose logging will be removed in the next release.
## [5.0.11] - 2020.03.05
### Fix
- adding debug logs for listening, and allowing to subscribers to listen to self
## [5.0.10] - 2020.03.05
### Fix
- Fixing log level output as debug logs are being ignored
## [5.0.9] - 2020.02.22
### Misc
- Attempt to fix npm publishing issue due to travis bug
## [5.0.8] - 2020.02.16
### Fixes
- Call onClientDisconnect with userId instead of socket
## [5.0.7] - 2020.02.08
### Fixes
- Fixes in storage auth handler by @abird
## [5.0.6] - 2020.02.08
### Improvement
- Updating all dependencies
### Fixes
- Call onClientDisconnect from combined auth handler
## [5.0.5] - 2019.11.24
### Feat
- Adding winston to docker and package image
### Fix
- Fixed critical issue where invalid websocket frames kill server
## [5.0.4] - 2019.11.05
### Fix
- Provide all HTTP headers to auth endpoint when using ws
## [5.0.3] - 2019.11.05
### Feat
- Adding a log monitoring plugin, useful for kibana log forwarding
- Adding header authentication for http monitoring
## [5.0.2] - 2019.11.04
### Fix
- Production only dependency did not include ds-types
- Close down MQTT server on stop
## [5.0.1] - 2019.11.02
### Features
- Replaces ENV variables in config loaded using fileLoader [#1022](https://github.com/deepstreamIO/deepstream.io/issues/1022)
### Fixes
- Fixes odd types scripting issue breaking plugin interfaces when using `deepstream.getServices()`
- Fixes hash generation via CLI [#1025](https://github.com/deepstreamIO/deepstream.io/issues/1025)
## [5.0.0] - 2019.10.27
### Features:
- New License
- Singular HTTP Service
- SSL Support reintroduced
- Better Config file validation
- JSON Logger
- NGINX Helper
- Combined authentication handler
- Embedded dependencies
- Builtin HTTP Monitoring
- Storage authentication endpoint
- Guess whats back, official clustering support!
### Backwards compatibility
- Custom authentication plugins now have to use the async/await API
- Custom permission handlers need to slightly tweak the function arguments
- Deployment configuration has to be (simplified) to respect the single HTTP/Websocket port
### Upgrade guide
You can see the upgrade guide for backwards compatibility [here](https://deepstream.io/tutorials/upgrade-guides/v5/server/)
## [4.2.5] - 2019.10.01
### Fix
Removing dom lib from typescript, which exposed variables that throw exceptions #1008
## [4.2.4] - 2019.10.01
### Fix
Cannot read property 'N' of undefined #920
## [4.2.3] - 2019.10.01
### Improvement
Hardening the config validator
### Fix
Allow empty password for mqtt endpoint when authentication is not enabled (@Aapkostka) #1003
ResolvePluginClass should look for lowercase plugins #1002
RPC not routed to different deepstream node depending on startup order #1001
### Misc
Updating dependencies
## [4.2.2] - 2019.09.17
### Fix
Adding health-checks for all ws based endpoints.
## [4.2.1] - 2019.09.17
### Fix
Remove conflicting port for those starting using node with an empty config object.
### Improvement
Limit the dead socket log to reduce insane spam.
## [4.2.0] - 2019.09.09
### Feat
Two new connection endpoints have been added. They are currently experimental and will be properly
announced with associated documentation.
One endpoint is mqtt! This allows us to support mqtt auth (using username and password), retain using records and QoS 1 using write acks. The only issue is since mqtt only supports one sort
of concept (with flags distinguishing them) we bridge both events and records together. That means if you subscribe to 'temperature/london', you'll get the update from both a client doing `event.emit('temperature/london')` and `record.setData('temperature/london')`.
The second endpoint is `ws-json` which allows users to interact with deepstream by just passing through json serialized text blobs instead of protobuf. This is mainly to help a few people trying to write SDKs without the hassle of a protobuf layer.
Value also injects a `name` variable which allows you to reference the name your currently in. Useful for cross referencing.
### Fix
Subscription registry seemed to have a massive leak when it came to dead sockets! This has now been fixed. The sockets seemed to have gotten the remove event deleted earlier in their lifecycle which prohibited it from doing a proper clean up later.
## [4.1.0] - 2019.08.30
### Feat
Backwards compatibility with V3 clients / text protocol using a ws-text connection endpoint
This has a couple of small differences, like `has` is no longer supported and `snapshot` errors
are exposed using the global `error` callback instead of via the response. Otherwise all the e2e
tests work, and best of all you can run both at the same time if you want to run JS 4.0
and Java 3.0 simultaneously!
It is worth keeping in mind there is a small CPU overhead between switching from V3 custom deepstream
encoding to JSON (V4), so it is advised to monitor your CPU when possible!
```
- type: ws-text
options:
# port for the websocket server
port: 6021
# host for the websocket server
host: 0.0.0.0
```
## [4.0.6] - 2019.08.19
### Feat
Allow SUBSCRIBE and READ without CREATE actions, for clients that are in read only mode
### Improvement
Adding declaration types (thank you @Vortex375!)
## [4.0.5] - 2019.08.09
### Improvement
Adding meta objects to logs and monitoring for easier tagging to monitoring solutions
## [4.0.4] - 2019.08.05
### Fix
- Don't buffer error messages in relation to connections, otherwise the client will get the close event first
- Ignore ping messages during the connecting and authenticating stages
## [4.0.3] - 2019.08.04
### Fix
- Notify monitoring plugin of all messages sent out individually
## [4.0.2] - 2019.08.03
### Features
- Alpine docker image
### Fix
- Override the http port and host correctly
## [4.0.1] - 2019.07.31
### Improvements
- Exit immediately if HTTP server port is occupied
- When using debug, log exact error to why a plugin could not be loaded
## [4.0.0] - 2019.07.30
### Features:
- New protobuf protocol support (under the hood)
- Bulk actions instead of individual subscribes (under the hood)
- Official Plugin Support
- Monitoring Support
- Clustering Support (with small caveats)
- Listening Discovery Simplification
- V2 storage API
- V2 cache API
- Notify API
### Improvements
- Lazy data parsing
- Improved deepstream lifecycle
- Upgraded development tools
- New deepstream.io website
### Backwards compatibility
- All V3 SDKs no longer compatible due to protobuf binary protocol
### Upgrade guide
You can see the upgrade guide for backwards compatibility [here](https://deepstream.io/tutorials/upgrade-guides/v4/server/)
### TLDR;
You can see the in depth side explanation of the changes [here](https://deepstream.io/releases/server/v4-0-0/)
## [3.1.0] - 2017.09.25
### Features
- a new standardised logging API with `debug`, `info`, `warn` and `error` methods
- the presence feature can now be used on a per user basis. The online status of individual users can be queried for as well as subscribed to. Check out the tutorial on our website [here](https://deepstreamhub.com/tutorials/guides/presence/)
### Improvements
- `perMessageDeflate` option can now be passed to uws, courtesy of [@daviderenger](@daviderenger) [#786](https://github.com/deepstreamIO/deepstream.io/pull/786)
- various fixes and performance improvements to the subscription registry [#780](https://github.com/deepstreamIO/deepstream.io/pull/780), courtesy of [@ronag](@ronag).
### Fixes
- allow updating and writing to Lists via the HTTP API [#788](https://github.com/deepstreamIO/deepstream.io/pull/788) courtesy of [@rbarroetavena](@rbarroetavena)
- no data when sending HTTP requests is now considered undefined, rather than null [#798](https://github.com/deepstreamIO/deepstream.io/pull/798).
### Miscellaneous
- internal refactor to pull e2e client operations into framework and abstract from Cucumber steps.
## [3.0.1] - 2017.08.14
### Features
- Added a `restart` option to deepstream service CLI
- deepstream will now write to a pid file at `/var/run/deepstream/deepstream.pid` while running as a service
- Authentication and permission plugins can now be configured via config and will be resolved as normal plugins. Either a path or name will need to be provided at the top level, and any options specified will also be passed in.
## [3.0.0] - 2017.07.26
### Features
#### [HTTP API](https://deepstreamhub.com/docs/http/v1/)
Enabling clients to create, read, update and delete records, emit events, request RPCS
and read presence using a JSON bulk request/response format via HTTP.
- The HTTP API is enabled by default on PORT 8080 and can be configured in the
connectionEndpoints -> http section of deepstream's `config.yml`
- To disable the HTTP API set the above config to null
#### [PHP Client Support](https://deepstreamhub.com/docs/client-php/DeepstreamClient/)
The above HTTP API makes deepstream.io compatible with the deepstream PHP client
#### Multi Endpoint Architecture
The deepstream 3.0 release lays the groundwork for multiple combinable endpoints/protocols,
e.g. GraphQL or Binary to be used together. It also introduces a new endpoint type enabling
developers to write their own. Please note - at the moment it is not possible to run multiple subscription
based endpoints (e.g. websocket) simultaneously.
#### Message Connector Discontinuation
To address the scalability issues associated with the message connector interface's coarse topics
deepstream will move to a build-in, high performance p2p/small world network based clustering approach, available
as an enterprise plugin. The current message connector support is discontinued.
### Miscellaneous
- Moved end-to-end tests into this repository from `deepstream.io-client-js`.
- Replaced `javascript-state-machine` dependency with custom state machine.
### Fixes
- Improved handling of invalid record names.
## [2.4.0] - 2017.07.01
## Features
- Added new CLI command, including:
+ deepstream daemon
This command forks deepstream and monitors it for crashes, allowing it to restart automatically to avoid downtime
+ deepstream service add
This command allows you to create an init.d or systemd script automatically and add it to your system.
```bash
sudo deepstream service --help
Usage: service [options] [add|remove|start|stop|status]
Add, remove, start or stop deepstream as a service to your operating system
```
- Added brew cask support
You can now install easily install deepstream on your mac using `brew cask install deepstream` driven by config files within `/user/local/etc/deepstream/conf`
## Fixes
- Fix issue where certain invalid paths would return 'Invalid Type' on the server.
- Fix issue in request/response where selecting a remote server as not done uniformly.
## [2.3.7] - 2017.06.20
## Fixes
- Fix issue where using both `.0.` and `[0]` within a json path resulted in inserting into an array. However, when using other SDKs such as Java they would be treated as an Object key or array index.
- Fix issue where nested array access/manipulation didn't work via json paths.
## Compatability Issue
Due to the nature of this fix, it may result in compatability issues with applications that used json paths incorrectly ( using `.0.` intead of `[0]` ). Please ensure you change those before upgrading.
## [2.3.6] - 2017.06.12
## Fixes
- Fix for issue [#703](https://github.com/deepstreamIO/deepstream.io/issues/703)
where record deletions were not being propogated correctly within a cluster.
- Fixes config-loading issue present in the binary release of 2.3.5.
## [2.3.5] - 2017.06.12
## Fixes
- Hardcode v3.0.0-rc1 dependency on javascript-state-machine, as v3.0.1 causes deepstream.io startup to fail
## [2.3.4] - 2017.06.02
## Fixes
- Hot path needs to store values in the correct format
## [2.3.3] - 2017.06.02
### Fixes
- Binary config files have the correct latest structure
- Fix an issue where heavy concurrent writes on the same record fail
## [2.3.2] - 2017.05.31
### Fixes
- Fixing a connection data regression where it wasn't formatted the same as pre 2.3.0
## [2.3.1] - 2017.05.30
### Fixes
- Correctly merging config options from `config.yml` file with the default options
## [2.3.0] - 2017.05.29
### Features
- Adds "storageHotPathPatterns" config option.
- Adds support for `setData()`: upsert-style record updates without requiring that a client is
subscribed to the record. This uses a new 'CU' (Create and Update) message. The `setData()` API
is up to 10x faster than subscribing, setting, then discarding a record.
- Support for connection endpoint plugins.
### Enhancements
- Significant performance improvements stemming from message batching.
### Miscellaneous
- Moved uws into a connection endpoint plugin.
- Explicit state-machine that initializes and closes dependencies in a well-defined order.
## [2.2.2] - 2017.05.03
### Enhancements
- Adds support for custom authentication and permissioning plugins.
- Adds support for generic plugins.
### Fixes
- Added check to ensure subscriptions are not removed from distributed state registry prematurely.
## [2.2.1] - 2017.04.24
### Enhancements
- Unsolicited RPCs now get a `INVALID_RPC_CORRELATION_ID` message
### Fixes
- RPC lifecycles have been improved and don't throw exceptions on response after a timeout by [ronag](ronag)
- Correct options now being passed into the `RuleCache`, courtesy of [ralphtheninja](ralphtheninja)
## [2.2.0] - 2017.04.08
### Enhancements
- Records now can be set with a version -1, which ignores version conflicts by [datasage](datasage)
- Delete events are now propagated in the correct order by [datasage](datasage)
- You can now request the HEAD of a record to retrieve just its version number by [datasage](datasage)
- Providers for listeners are now by default selected randomly instead of in order of subscription
- Ensure record updates are not scalar values before trying to save them in cache by [datasage](datasage)
- Long lived RPC requests now use dynamic lookups for providers rather than building the Set upfront by [ronag]{ronag}
- Huge optimization to subscription registry, where the time for registering a subscriber has been reduced from n^2 to O(n log n)
### Miscellaneous
- Deleting grunt since everything is script based
## [2.1.6] - 2017.03.29
### Miscellaneous
- Due to uws releases being pulled from NPM, we're now using uws from a git repo
- Created a separate repo [uws-dependency](https://github.com/deepstreamIO/uws-dependency) with binaries.
## [2.1.4 - 2.1.5]
- Due to problems with build resulting from uws unpublishing, these two npm packages
have been unpublished (noop)
## [2.1.3] - 2017.02.25
### Bug Fixes
- Unsolicited message in Listening when all clients unsubscribe [#531]
- Handle Non text based websocket frame [#538]
- Aligning binary config with node [#488]
- Event subscription data mishandled in Valve [#510]
- Logging after logger is destroyed [#527]
- Deepstream crash on empty users file [#512]
- Logging error object instead of name in connection error [#420]
### Enhancements
- maxRuleIterations must be 1 or higher [#498]
- Ignore sender in subscriptionRegistry if messagebus [#473]
- Removing dead config options [#599]
- getAlternativeProvider in RPC Handler deals with more edge cases [#566]
- Update UWS build version to 0.12
- Packages built against node 6.10
## [2.1.2] - 2016.12.28
### Bug fixes
- Fixing write error where only initial value is written to storage [#517](https://github.com/deepstreamIO/deepstream.io/issues/517)
## [2.1.1] - 2016.12.28
### Bug fixes
- Valve cross referencing in both a create and read results in a ack timeout [#514](https://github.com/deepstreamIO/deepstream.io/issues/514)
## [2.1.0] - 2016.12.20
### Features
- Record write acknowledgement. Records are now able to be set with an optional callback which will be called with any errors from storing the record in cache/storage [#472](https://github.com/deepstreamIO/deepstream.io/pull/472)
### Enhancements
- Applying an ESLint rule set to the repo [#482](https://github.com/deepstreamIO/deepstream.io/pull/482)
- Stricter valve permissioning language checks [#486](https://github.com/deepstreamIO/deepstream.io/pull/486) by [@Iiridayn](https://github.com/Iiridayn)
- Update uWS version to [v0.12.0](https://github.com/uWebSockets/uWebSockets/releases/tag/v0.12.0)
### Bug fixes
- Better handling/parsing of authentication messages [#463](https://github.com/deepstreamIO/deepstream.io/issues/463)
- Properly returning handshake data (headers) from SocketWrapper [#450](https://github.com/deepstreamIO/deepstream.io/issues/450)
- Fix case where CLIENT_DISCONNECTED is not sent from SocketWrapper [#470](https://github.com/deepstreamIO/deepstream.io/issues/470)
- Fixed issue where listen does not recover from server restart [#476](https://github.com/deepstreamIO/deepstream.io/issues/476)
- Handling presence events properly. Now when a user logs in, subscribed clients are only notified the first time the user logs in, and the last time they log out [#499](https://github.com/deepstreamIO/deepstream.io/pull/499)
## [2.0.1] - 2016.11.21
### Bug Fixes
- Fixed issue where connectionData was not available in auth requests
[#450](https://github.com/deepstreamIO/deepstream.io/issues/450)
- Changelog of 2.0.0 mistakenly said that heartbeats were on port 80 instead of 6020
## [2.0.0] - 2016.11.18
### Features
- User presence has been added, enabling querying and subscription to who is
online within a cluster
- Introduces the configuration option `broadcastTimeout` to `config.yml` to allow coalescing of
broadcasts. This option can be used to improve broadcast message latency such
as events, data-sync and presence
For example, the performance of broadcasting 100 events to 1000 subscribers
was improved by a factor of 20
- Adds client heartbeats, along with configuration option`heartbeatInterval` in `config.yml`.
If a connected client fails to send a heartbeat within this timeout, it will be
considered to have disconnected [#419](https://github.com/deepstreamIO/deepstream.io/issues/419)
- Adds healthchecks – deepstream now responds to http GET requests to path
`/health-check` on port 6020 with code 200. This path can be configured with
the `healthCheckPath` option in `config.yml`
### Enhancements
- E2E tests refactored
- uWS is now compiled into the deepstream binary, eliminating reliability
issues caused by dynamic linking
### Breaking Changes
- Clients prior to v2.0.0 are no longer compatible
- Changed format of RPC request ACK messages to be more consistent with the
rest of the specs
[#408](https://github.com/deepstreamIO/deepstream.io/issues/408)
- We removed support for TCP and engine.io, providing huge performance gains by
integrating tightly with native uWS
- Support for webRTC has been removed
- You can no longer set custom data transforms directly on deepstream
## [1.1.2] - 2016-10-17
### Bug Fixes
- Sending an invalid connection message is not caught by server [#401](https://github.com/deepstreamIO/deepstream.io/issues/401)
## [1.1.1] - 2016-09-30
### Bug Fixes
- Storage connector now logs errors with the correct namepspace [@Iiridayn](@Iiridayn)
### Enhancements
- RPC now uses distributed state and no longer depends on custom rpc discovery logic
- Deepstream now uses connection challenges by default rather than automatically replying with an ack
- Upgraded to uWS 0.9.0
## [1.1.0] - 2016-09-08
### Bug Fixes
- Fix wrong validation of Valve Permissions when `data` is used as a property [#346](https://github.com/deepstreamIO/deepstream.io/pull/346)
### Enhancements
- Outgoing connections now have throttle options that allow you to configure maximum package sizes to find your personal sweet spot between latency and speed
```yaml
# the time (in milliseconds) to wait for a buffer to fill before sending it out
timeBetweenSendingQueuedPackages: 1
# the amount of messages that should fit into a buffer before sending between the time to fill
maxMessagesPerPacket: 1000
```
### Features
- Listening: Listeners have been drastically improved [https://github.com/deepstreamIO/deepstream.io/issues/211], and now:
- works correctly across a cluster
- can inform the user whenever the last subscription has been removed even if the listener itself is subscribed
- only allows a single listener to provide a record
- has a concept of provided, allowing records on the client side to be aware if the data is being actively updated by a backend component
As part of this story, we now have multiple significant improvements in the server itself, such as:
- a `distributed state registry` which allows all clusters to keep their state in sync
- a `unique state provider` allowing cluster wide locks
- a `cluster-registry` that provides shares server presence and state across the cluster
Because of these we can now start working on some really cool features such as advanced failover, user presence and others!
## [1.0.4] - 2016-08-16
### Bug Fixes
- Auth: File authentication sends server data to client on cleartext passwords [#322](https://github.com/deepstreamIO/deepstream.io/issues/322)
- Auth: HTTP authentication missing logger during when attempting to log any errors occured on http server [#320](https://github.com/deepstreamIO/deepstream.io/issues/320)
## [1.0.3] - 2016-07-28
### Bug Fixes
- CLI: installer for connectors sometimes fail to download (and extract) the archive [#305](https://github.com/deepstreamIO/deepstream.io/issues/305)
- Auth: File authentication doesn't contain `serverData` and `clientData` [#304](https://github.com/deepstreamIO/deepstream.io/issues/304)
###### Read data using `FileAuthentication` using clientData and serverData rather than data
```yaml
userA:
password: tsA+yfWGoEk9uEU/GX1JokkzteayLj6YFTwmraQrO7k=75KQ2Mzm
serverData:
role: admin
clientData:
nickname: Dave
```
### Features
###### Make connection timeout
Users can now provide a `unauthenticatedClientTimeout` config option that forces connections to close if they don't authenticate in time.
This helps reduce load on server by terminating idle connections.
- `null`: Disable timeout
- `number`: Time in milliseconds before connection is terminated
## [1.0.2] - 2016-07-19
### Bug Fixes
- Fixed issue regarding last subscription to a deleted record not being cleared up
## [1.0.1] - 2016-07-18
### Bug Fixes
- Fix issue when try to pass options to the default logger [#288](https://github.com/deepstreamIO/deepstream.io/pull/288) ([update docs](https://github.com/deepstreamIO/deepstream.io-website/pull/35/commits/838617d93cf00e66176cdf06d161fd8f86574aa1) as well)
- Fix issue deleting a record does not unsubscribe it and all other connections, not allowing resubscriptions to occur #293
#### Enhancements
###### Throw better error if dependency doesn't implement Emitter or isReady
## [1.0.0] - 2016-07-09
### Features
###### CLI
You can start deepstream via a command line interface. You find it in the _bin_ directory. It provides these subcommands:
- `start`
- `stop`
- `status`
- `install`
- `info`
- `hash`
append a `--help` to see the usage.
###### File based configuration
You can now use a file based configuration instead of setting options via `ds.set(key, value)`.
deepstream is shipped with a _conf_ directory which contains three files:
- __config.yml__ this is the main config file, you can specify most of the deepstream options in that file
- __permissions.yml__ this file can be consumed by the PermissionHandler. It's not used by default, but you can enable it in the _config.yml_
- __users.yml__ this file can be consumed by the AuthenticationHandler. It's not used by default, but you can enable it in the _config.yml_
For all config types support these file types: __.yml__, __.json__ and __.js__
###### Constructor API
There are different options what you can pass:
- not passing any arguments ( consistent with 0.x )
- passing `null` will result in loading the default configuration file in the directory _conf/config.yml_
- passing a string which is a path to a configuration file, supported formats: __.yml__, __.json__ and __.js__
- passing an object which defines several options, all other options will be merged from deepstream's default values
###### Valve Permissions rules
You can write your permission into a structured file. This file supports a special syntax, which allows you to do advanced permission checks. This syntax is called __Valve__.
#### Enhancements
###### uws
deepstream now uses [uws](https://github.com/uWebSockets/uWebSockets), a native C++ websocket server
###### no process.exit on plugin initialization error or timeout
deepstream will not longer stops your process via `process.exit()`. This happened before when a connector failed to initialize correctly [#243](https://github.com/deepstreamIO/deepstream.io/issues/243) instead it will throw an error now.
Currently the API provides no event or callback to handle this error
other than subscribing to the global `uncaughtException` event.
```javascript
process.once('uncaughtException', err => {
// err.code will equal to of these constant values:
// C.EVENT.PLUGIN_INITIALIZATION_TIMEOUT
// or C.EVENT.PLUGIN_INITIALIZATION_ERROR
})
```
Keep in mind that deepstream will be in an unpredictable state and you should consider to create a new instance.
### Breaking Changes
###### Permission Handler
In 0.x you can set a `permissionHandler` which needs to implement two functions:
- `isValidUser(connectionData, authData, callback)`
- `canPerformAction(username, message, callback)`
In deepstream 1.0 the `isValidUser` and `onClientDisconnect` methods are no longer part of the `permissionHandler` and are instead within the new `authenticationHandler`.
You can reuse the same 0.x permission handler except you will have to set it on both explicitly.
```javascript
const permissionHandler = new CustomPermissionHandler()
ds.set( 'permissionHandler', permissionHandler )
ds.set( 'authenticationHandler', permissionHandler )
```
###### Plugin API
All connectors including, the `permissionHandler`, `authenticationHandler` and `logger` all need to implement the plugin interface which means exporting an object that:
- has a constructor
- has an `isReady` property which is true once the connector has been initialized. For example in the case a database connector this would only be `true` once the connection has been established. If the connector is synchronous you can set this to true within the constructor.
- extends the EventEmitter, and emits a `ready` event once initialized and `error` on error.
###### Logger and colors options
The color flag can't be set in the root level of the configuration anymore.
The default logger will print logs to the StdOut/StdErr in colors.
You can use the [deepstream.io-logger-winston](https://www.npmjs.com/package/deepstream.io-logger-winston) which can be configured in the config.yml file with several options.
###### Connection redirects
deepstream clients now have a handshake protocol which allows them to be redirected to the most efficient node and expect an initial connection ack before logging in. As such In order to connect a client to deepstream server you need also to have a client with version 1.0 or higher.
More details in the [client changelog](https://github.com/deepstreamIO/deepstream.io-client-js/blob/master/CHANGELOG.md).
================================================
FILE: Dockerfile
================================================
FROM node:22 as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
RUN npm install --omit=dev \
@deepstream/cache-redis \
# @deepstream/cache-memcached \
# @deepstream/cache-hazelcast \
@deepstream/clusternode-redis \
@deepstream/storage-mongodb \
@deepstream/storage-rethinkdb \
@deepstream/storage-elasticsearch \
@deepstream/storage-postgres \
@deepstream/logger-winston \
@deepstream/plugin-aws
COPY . .
RUN npm run tsc
FROM node:22
WORKDIR /usr/local/deepstream
COPY --from=builder /app/node_modules/ ./node_modules
COPY --from=builder /app/dist/ .
EXPOSE 6020
EXPOSE 8080
EXPOSE 9229
CMD ["node", "./bin/deepstream.js", "start", "--inspect=0.0.0.0:9229"]
================================================
FILE: Dockerfile.alpine
================================================
FROM node:22-alpine as builder
WORKDIR /app
# RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
# RUN unzip awscliv2.zip
# RUN ./aws/install
COPY package*.json ./
RUN npm ci
RUN npm install --omit=dev \
@deepstream/cache-redis \
# @deepstream/cache-memcached \
# @deepstream/cache-hazelcast \
@deepstream/clusternode-redis \
@deepstream/storage-mongodb \
@deepstream/storage-rethinkdb \
@deepstream/storage-elasticsearch \
@deepstream/storage-postgres \
@deepstream/logger-winston \
@deepstream/plugin-aws
RUN npm uninstall --save uWebSockets.js
COPY . .
RUN npm run tsc
FROM node:22-alpine
WORKDIR /usr/local/deepstream
COPY --from=builder /app/node_modules/ ./node_modules
COPY --from=builder /app/dist/ .
EXPOSE 6020
EXPOSE 8080
EXPOSE 9229
CMD ["node", "./bin/deepstream.js", "start", "--inspect=0.0.0.0:9229"]
================================================
FILE: LICENSE
================================================
Copyright 2019 deepstreamHub GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
# deepstream - the open realtime server <a href='https://deepstreamio.github.io/'><img src='./elton-square.png' height='60' alt='deepstream'></a>
deepstream is an open source server inspired by concepts behind financial trading technology. It allows clients and backend services to sync data, send messages and make rpcs at very high speed and scale.
[](https://badge.fury.io/js/%40deepstream%2Fserver)[](https://hub.docker.com/r/deepstreamio/deepstream.io/)
deepstream has three core concepts for enabling realtime application development
- **records** ([realtime document sync](https://deepstreamio.github.io/docs/tutorials/core/datasync/records))
records are schema-less, persistent documents that can be manipulated and observed. Any change is synchronized with all connected clients and backend processes in milliseconds. Records can reference each other and be arranged in lists to allow modelling of relational data
- **events** ([publish subscribe messaging](https://deepstreamio.github.io/docs/tutorials/core/pubsub/events))
events allow for high performance, many-to-many messaging. deepstream provides topic based routing from sender to subscriber, data serialisation and subscription listening.
- **rpcs** ([request response workflows](https://deepstreamio.github.io/docs/tutorials/core/request-response/rpc))
remote procedure calls allow for secure and highly available request response communication. deepstream handles load-balancing, failover, data-transport and message routing.
- **security** ([Authentication](https://deepstreamio.github.io/docs/tutorials/core/auth/auth-introduction) and [Permissions](https://deepstreamio.github.io/docs/tutorials/core/permission/valve-introduction))
deepstream offers a combination of different authentication mechanisms with a powerful permission-language called Valve that allows you to specify which user can perform which action with which data.
### Getting Started:
1. [Tutorials - What is deepstream](https://deepstreamio.github.io/docs/tutorials/concepts/what-is-deepstream)
2. [Installing deepstream](https://deepstreamio.github.io/docs/tutorials/install/linux)
3. [Quickstart](https://deepstreamio.github.io/docs/tutorials/getting-started/javascript)
4. [Documentation](https://deepstreamio.github.io/docs/docs)
### Community Links
1. [Stack Overflow](https://stackoverflow.com/questions/tagged/deepstream.io)
2. [Github Discussions](https://github.com/deepstreamIO/deepstreamIO.github.io/discussions)
### Contributing
deepstream development is a great way to get into building performant Node.js applications, and contributions are always welcome with lots of ❤. Contributing to deepstream is as simple as having Node.js (10+) and TypeScript (3+) installed, cloning the repo and making some changes.
```
~ » git clone git@github.com:deepstreamIO/deepstream.io.git
~ » cd deepstream.io
~/deepstream.io » git submodule update --init
~/deepstream.io » npm i
~/deepstream.io » npm start
_ _
__| | ___ ___ _ __ ___| |_ _ __ ___ __ _ _ __ ____
/ _` |/ _ \/ _ \ '_ \/ __| __| '__/ _ \/ _` | '_ ` _ \
| (_| | __/ __/ |_) \__ \ |_| | | __/ (_| | | | | | |
\__,_|\___|\___| .__/|___/\__|_| \___|\__,_|_| |_| |_|
|_|
===================== starting =====================
```
From here you can make your changes, and check the unit tests pass:
```
~/deepstream.io » npm t
```
If your changes are substantial you can also run our extensive end-to-end testing framework:
```
~/deepstream.io » npm run e2e
```
For power users who want to make sure the binary works, you can run `sh scripts/package.sh true`. You'll need to download the usual [node-gyp](https://github.com/nodejs/node-gyp) build environment for this to work and we only support the latest LTS version to compile. This step is usually not needed though unless your modifying resource files or changing dependencies.
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Reporting a Vulnerability
Report the vulnerability in the security [advisory section](https://github.com/deepstreamIO/deepstream.io/security) of the repository.
If your submission is valid, a GitHub advisory will be published and if present in NPM or other released packages, a CVE will be requested.
================================================
FILE: ascii-logo.txt
================================================
_ _
__| | ___ ___ _ __ ___| |_ _ __ ___ __ _ _ __ ____
/ _` |/ _ \/ _ \ '_ \/ __| __| '__/ _ \/ _` | '_ ` _ \
| (_| | __/ __/ |_) \__ \ |_| | | __/ (_| | | | | | |
\__,_|\___|\___| .__/|___/\__|_| \___|\__,_|_| |_| |_|
|_|
================================================
FILE: bin/deepstream-cluster.ts
================================================
import { Command } from 'commander'
import * as cluster from 'cluster'
const numCPUs = require('os').cpus().length
import { EVENT } from '@deepstream/types'
export const verticalCluster = (program: Command) => {
program
.command('cluster')
.description('start a vertical cluster of deepstream servers')
.option('-c, --config [file]', 'configuration file, parent directory will be used as prefix for other config files')
.option('-l, --lib-dir [directory]', 'path where to lookup for plugins like connectors and logger')
.option('--cluster-size <amount>', 'the amount of nodes to run in the cluster. Defaults to all available cores')
.option('--host <host>', 'host for the http service')
.option('--port <port>', 'port for the http service')
.option('--disable-auth', 'Force deepstream to use "none" auth type')
.option('--disable-permissions', 'Force deepstream to use "none" permissions')
.option('--log-level <level>', 'Log messages with this level and above')
.action(action)
}
function action () {
// @ts-ignore
global.deepstreamCLI = this
const workers = new Set<any>()
if (!global.deepstreamCLI.clusterSize) {
global.deepstreamCLI.clusterSize = numCPUs
}
if (global.deepstreamCLI.clusterSize && global.deepstreamCLI.clusterSize > numCPUs) {
console.warn('Setting more nodes than available cores can decrease performance')
}
const setupWorkerProcesses = () => {
console.log('Master cluster setting up ' + global.deepstreamCLI.clusterSize + ' deepstream nodes')
for (let i = 0; i < global.deepstreamCLI.clusterSize; i++) {
workers.add(cluster.fork())
}
// process is clustered on a core and process id is assigned
cluster.on('online', (worker) => {
console.log(`Deepstream ${worker.process.pid} is listening`)
})
// if any of the worker process dies then start a new one by simply forking another one
cluster.on('exit', (worker, code, signal) => {
console.log(`Deepstream ${worker.process.pid} died with code: ${code}, and signal: ${signal}`)
console.log('Starting a new worker')
workers.delete(worker)
workers.add(cluster.fork())
})
}
// if it is a master process then call setting up worker process
// @ts-ignore
if (cluster.isPrimary) {
setupWorkerProcesses()
} else {
const { Deepstream } = require('../src/deepstream.io')
try {
const ds = new Deepstream(null)
ds.on(EVENT.FATAL_EXCEPTION, () => process.exit(1))
ds.start()
process
.removeAllListeners('SIGINT').on('SIGINT', () => {
ds.on('stopped', () => process.exit(0))
ds.stop()
})
} catch (err: any) {
console.error(err.toString())
process.exit(1)
}
}
}
================================================
FILE: bin/deepstream-daemon.ts
================================================
// @ts-ignore
import * as dsDaemon from '../src/service/daemon'
import { Command } from 'commander'
export const daemon = (program: Command) => {
program
.command('daemon')
.description('start a daemon for deepstream server')
.option('-c, --config [file]', 'configuration file, parent directory will be used as prefix for other config files')
.option('-l, --lib-dir [directory]', 'path where to lookup for plugins like connectors and logger')
.option('--host <host>', 'host for the http service')
.option('--port <port>', 'port for the http service')
.option('--disable-auth', 'Force deepstream to use "none" auth type')
.option('--disable-permissions', 'Force deepstream to use "none" permissions')
.option('--log-level <level>', 'Log messages with this level and above')
.action(action)
}
function action () {
dsDaemon.start({ processExec: process.argv[1] })
}
================================================
FILE: bin/deepstream-hash.ts
================================================
import * as jsYamlLoader from '../src/config/js-yaml-loader'
import { Command } from 'commander'
import { createHash } from '../src/utils/utils'
export const hash = (program: Command) => {
program
.command('hash [password]')
.description('Generate a hash from a plaintext password using file auth configuration settings')
.option('-c, --config [file]', 'configuration file containing file auth and hash settings')
.action(action)
}
async function action (this: any, password: string) {
// @ts-ignore
global.deepstreamCLI = this
const config = (await jsYamlLoader.loadConfigWithoutInitialization()).config
const fileAuthHandlerConfig = config.auth.find((auth) => auth.type === 'file')
if (fileAuthHandlerConfig === undefined) {
console.error('Error: Can only use hash with file authentication as auth type')
return process.exit(1)
}
if (!fileAuthHandlerConfig.options.hash) {
console.error('Error: Can only use hash with file authentication')
return process.exit(1)
}
fileAuthHandlerConfig.options.path = ''
if (!password) {
console.error('Error: Must provide password to hash')
return process.exit(1)
}
const { iterations, keyLength, hash: algorithm } = fileAuthHandlerConfig.options
try {
const { hash: generatedHash, salt } = await createHash(password, { iterations, keyLength, algorithm })
console.log(`Password hash: ${generatedHash.toString('base64')}${salt}`)
} catch (e) {
console.error('Hash could not be created', e)
process.exit(1)
}
}
================================================
FILE: bin/deepstream-info.ts
================================================
import * as jsYamlLoader from '../src/config/js-yaml-loader'
import { Command } from 'commander'
import { getDSInfo } from '../src/config/ds-info'
export const info = (program: Command) => {
program
.command('info')
.description('print meta information about build and runtime')
.option('-c, --config [file]', 'configuration file containing lib directory')
.option('-l, --lib-dir [directory]', 'directory of libraries')
.action(printMeta)
}
async function printMeta (this: any) {
if (!this.libDir) {
try {
// @ts-ignore
global.deepstreamCLI = this
await jsYamlLoader.loadConfigWithoutInitialization()
// @ts-ignore
this.libDir = global.deepstreamLibDir
} catch (e) {
console.log(e)
console.error('Please provide a libDir or a configFile to provide the relevant install information')
process.exit(1)
}
}
const dsInfo = await getDSInfo(this.libDir)
console.log(JSON.stringify(dsInfo, null, 2))
}
================================================
FILE: bin/deepstream-nginx.ts
================================================
// @ts-ignore
import * as dsService from '../src/service/service'
import { Command } from 'commander'
import { writeFileSync } from 'fs'
import * as jsYamlLoader from '../src/config/js-yaml-loader'
import * as fileUtil from '../src/config/file-utils'
export const nginx = (program: Command) => {
program
.command('nginx')
.description('Generate an nginx config file for deepstream')
.option('-c, --config [file]', 'The deepstream config file')
.option('-p, --port', 'The nginx port, defaults to 8080')
.option('-h, --host', 'The nginx host, defaults to localhost')
.option('--ssl', 'If ssl encryption should be added')
.option('--ssl-cert', 'The SSL Certificate')
.option('--ssl-key', 'The SSL Key')
.option('-o, --output [file]', 'The file to save the configuration to')
.action(execute)
}
async function execute (this: any, action: string) {
// @ts-ignore
global.deepstreamCLI = this
const { config: dsConfig } = await jsYamlLoader.loadConfigWithoutInitialization()
if (this.ssl && (!this.sslCert || !this.sslKey)) {
console.error('Missing --ssl-cert or/key --ssl-key options')
process.exit(1)
}
const sslConfig = `
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_certificate ${this.sslCert};
ssl_certificate_key ${this.sslKey};
`
const websocketConfig = dsConfig.connectionEndpoints.reduce((result: string, endpoint: any) => {
if (endpoint.options.urlPath) {
return result + `
location ${endpoint.options.urlPath} {
proxy_pass http://deepstream;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
`
}
return result
}, '')
let httpConfig = ''
const http = dsConfig.connectionEndpoints.find((endpoint: any) => endpoint.type === 'http')
if (http) {
const paths = new Set([http.options.getPath, http.options.postPath, http.options.authPath])
httpConfig = [...paths].reduce((result, path) => {
return result + `
location ${path} {
proxy_pass http://deepstream;
proxy_http_version 1.1;
}
`
}, '')
}
const config = `
worker_processes 1;
events {
worker_connections 1024;
}
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream deepstream {
server ${dsConfig.httpServer.options.host}:${dsConfig.httpServer.options.port};
# Insert more deepstream hosts / ports here for clustering to magically work
}
server {
listen ${this.port || 8080}${this.ssl ? ' ssl' : ''};
server_name ${this.serverName || 'localhost'};
${this.ssl ? sslConfig : ''}
${websocketConfig}
${httpConfig}
}
}`
if (this.output) {
writeFileSync(fileUtil.lookupConfRequirePath(this.output), config, 'utf8')
console.log(`Configuration written to ${fileUtil.lookupConfRequirePath(this.output)}`)
} else {
console.log(config)
}
}
================================================
FILE: bin/deepstream-service.ts
================================================
// @ts-ignore
import * as dsService from '../src/service/service'
import { Command } from 'commander'
export const service = (program: Command) => {
program
.command('service [add|remove|start|stop|restart|status]')
.description('Add, remove, start or stop deepstream as a service to your operating system')
.option('-c, --config [file]', 'configuration file, parent directory will be used as prefix for other config files')
.option('-n, --service-name <name>', 'the name to register the service')
.option('-l, --log-dir <directory>', 'the directory for output logs')
.option('-p, --pid-directory <directory>', 'the directory for the pid file')
.option('--dry-run', 'outputs the service file to screen')
.action(execute)
}
function response (error: Error | string | null, result: string) {
if (error) {
console.log(error)
} else {
console.log(result)
}
}
function execute (this: any, action: string) {
const name = this.serviceName || 'deepstream'
if (action === 'add') {
if (!this.logDir || !this.config) {
console.error('Please provide the config and log directory when adding a service')
process.exit(1)
}
const options = {
exec: process.argv[1],
programArgs: [] as string[],
pidFile: this.pidFile || `/var/run/deepstream/${name}.pid`,
logDir: this.logDir,
dryRun: this.dryRun
}
if (this.config) {
options.programArgs.push('-c')
options.programArgs.push(this.config)
}
dsService.add (name, options, response)
} else if (action === 'remove') {
dsService.remove (name, response)
} else if (action === 'start' ) {
dsService.start (name, response)
} else if (action === 'stop' ) {
dsService.stop (name, response)
} else if (action === 'status') {
dsService.status(name, response)
} else if (action === 'restart') {
dsService.restart(name, response)
} else {
console.log('Unknown action for service, please "add", "remove", "start", "stop", "restart" or "status"')
}
}
================================================
FILE: bin/deepstream-start.ts
================================================
import { Command } from 'commander'
import { EVENT } from '@deepstream/types'
export const start = (program: Command) => {
program
.command('start', { isDefault: true })
.description('start a deepstream server')
.option('-c, --config [file]', 'configuration file, parent directory will be used as prefix for other config files')
.option('-l, --lib-dir [directory]', 'path where to lookup for plugins like connectors and logger')
.option('--host <host>', 'host for the http service')
.option<number>('--port <port>', 'port for the http service', (value: string) => parseInteger('--port', value))
.option('--disable-auth', 'Force deepstream to use "none" auth type')
.option('--disable-permissions', 'Force deepstream to use "none" permissions')
.option<string>('--log-level <level>', 'Log messages with this level and above', parseLogLevel)
.option<boolean>('--colors [true|false]', 'Enable or disable logging with colors', (value: string) => parseBoolean('--colors', value))
.option('--inspect <url>', 'Enable node inspector')
.action(action)
}
function action () {
// @ts-ignore
global.deepstreamCLI = this
// @ts-ignore
const inspectUrl = global.deepstreamCLI.inspect
if (inspectUrl) {
const inspector = require('inspector')
// @ts-ignore
const [host, port] = global.deepstreamCLI.inspect.split(':')
if (!host || !port) {
throw new Error('Invalid inspect url, please provide host:port')
}
inspector.open(port, host)
}
const { Deepstream } = require('../src/deepstream.io')
try {
const ds = new Deepstream(null)
ds.on(EVENT.FATAL_EXCEPTION, () => process.exit(1))
ds.start()
process
.removeAllListeners('SIGINT').on('SIGINT', () => {
ds.on('stopped', () => process.exit(0))
ds.stop()
})
} catch (err) {
console.error(err?.toString())
process.exit(1)
}
}
/**
* Used by commander to parse the log level and fails if invalid
* value is passed in
*/
function parseLogLevel (logLevel: string) {
if (!/debug|info|warn|error|off/i.test(logLevel)) {
console.error('Log level must be one of the following (debug|info|warn|error|off)')
process.exit(1)
}
return logLevel.toUpperCase()
}
/**
* Used by commander to parse numbers and fails if invalid
* value is passed in
*/
function parseInteger (name: string, port: string) {
const portNumber = Number(port)
if (!portNumber) {
console.error(`Provided ${name} must be an integer`)
process.exit(1)
}
return portNumber
}
/**
* Used by commander to parse boolean and fails if invalid
* value is passed in
*/
function parseBoolean (name: string, enabled: string) {
let isEnabled
if (typeof enabled === 'undefined' || enabled === 'true') {
isEnabled = true
} else if (typeof enabled !== 'undefined' && enabled === 'false') {
isEnabled = false
} else {
console.error(`Invalid argument for ${name}, please provide true or false`)
process.exit(1)
}
return isEnabled
}
================================================
FILE: bin/deepstream.ts
================================================
#!/usr/bin/env node
import * as pgk from '../package.json'
import { Command } from 'commander'
import { start } from './deepstream-start'
import { info } from './deepstream-info'
import { hash } from './deepstream-hash'
import { service } from './deepstream-service'
import { daemon } from './deepstream-daemon'
import { verticalCluster } from './deepstream-cluster'
import { nginx } from './deepstream-nginx'
const program = new Command('deepstream')
program
.usage('[command]')
.version(pgk.version.toString())
start(program)
info(program)
hash(program)
service(program)
daemon(program)
verticalCluster(program)
nginx(program)
program.parse(process.argv)
================================================
FILE: conf/config.yml
================================================
# General
# Each server within a cluster needs a unique name. Set to UUID to have deepstream autogenerate a unique id
serverName: UUID
# Show the deepstream logo on startup
showLogo: true
# Plugin startup timeout – deepstream init will fail if any plugins fail to emit a 'done' event within this timeout
dependencyInitializationTimeout: 5000
# Directory where all plugins reside
#libDir: ../lib
# Exit the process a fatal error occurs, like losing a cache connection
exitOnFatalError: false
# Log messages with this level and above. Valid levels are 0 (DEBUG), 1 (INFO), 2 (WARN), 3 (ERROR), 4 (FATAL), 100(OFF)
logLevel: 0
# This disables specific feature in DS, which is a more performant way
# than disabling via permissions and is also how telemetry figures out
# what features are enabled
enabledFeatures:
record: true
event: true
rpc: true
presence: true
telemetry:
type: deepstreamIO
options:
# Disable telemetry entirely
enabled: false
# Prints whatever will be sent to the telemetry endpoint,
# without actually sending it
debug: false
# An anonymous uuid that allows us to know its one unique
# deployment. Please don't generate these randomly if using
# node, it really skews up analytics.
# deploymentId: <uuid goes here>
rpc:
# Timeout for client RPC acknowledgement
ackTimeout: 1000
# Timeout for actual RPC provider response
responseTimeout: 10000
# Don't send requestorName by default.
provideRequestorName: false
# Don't send requestorData by default.
provideRequestorData: false
record:
# Maximum time permitted to fetch from cache
cacheRetrievalTimeout: 30000
# Maximum time permitted to fetch from storage
storageRetrievalTimeout: 30000
# A list of prefixes that, when a record starts with one of the prefixes the
# records data won't be stored in the db
# storageExclusionPrefixes:
# - no-storage/
# - temporary-data/
# A list of prefixes that, when a record is updated via setData and it matches one of the prefixes
# it will be permissioned and written directly to the cache and storage layers
# storageHotPathPrefixes:
# - analytics/
# - metrics/
# Invalid configuration: data should NOT have additional properties
listen:
# Try finding a provider randomly rather than by the order they subscribed to.
shuffleProviders: true
# The amount of time to wait for a provider to acknowledge or reject a listen request
responseTimeout: 500
# The amount of time before trying to reattempt finding matches for subscriptions. This
# is not a cheap operation so it's recommended to raise keep this at minutes rather then
# second intervals if you are experiencing heavy loads
rematchInterval: 60000
# The amount of time a server will refuse to retry finding a subscriber after a previously
# failed attempt. This is used to avoid servers constantly trying to find a match without a
# cooldown period
matchCooldown: 10000
httpServer:
type: default
options:
# url path for http health-checks, GET requests to this path will return 200 if deepstream is alive
healthCheckPath: /health-check
# -- CORS --
# if disabled, only requests with an 'Origin' header matching one specified under 'origins'
# below will be permitted and the 'Access-Control-Allow-Credentials' response header will be
# enabled
allowAllOrigins: true
# maximum allowed size of a POST request body, in bytes, defaults to 1 MB
maxMessageSize: 1048576
# a list of allowed origins
origins:
- 'https://example.com'
# Options required to create an ssl app
# ssl:
# key: fileLoad(ssl/key.pem)
# cert: fileLoad(ssl/cert.pem)
# ca: ...
# type: uws
# options:
# # url path for http health-checks, GET requests to this path will return 200 if deepstream is alive
# healthCheckPath: /health-check
# # -- CORS --
# # if disabled, only requests with an 'Origin' header matching one specified under 'origins'
# # below will be permitted and the 'Access-Control-Allow-Credentials' response header will be
# # enabled
# allowAllOrigins: true
# # a list of allowed origins
# origins:
# - 'https://example.com'
# # maximum allowed size of a POST request body, in bytes, defaults to 1 MB
# maxMessageSize: 1048576
# # Headers to copy over from websocket
# headers:
# - user-agent
# # Options required to create an ssl app
# ssl:
# key: file(ssl/key.pem)
# cert: file(ssl/cert.pem)
# ## dhParams: ...
# ## passphrase: ...
# Connection Endpoint Configuration
# to disable, replace configuration with null eg. `http: null`
connectionEndpoints:
- type: ws-binary
options:
# url path websocket connections connect to
urlPath: /deepstream
# the amount of milliseconds between each ping/heartbeat message
heartbeatInterval: 30000
# the amount of milliseconds that writes to sockets are buffered
outgoingBufferTimeout: 0
# the maximum amount of bytes to buffer before flushing, stops the client from large enough packages
# to block its responsiveness
maxBufferByteSize: 100000
# Security
# should the server log invalid auth data, defaults to false
logInvalidAuthData: false
# amount of time a connection can remain open while not being logged in
unauthenticatedClientTimeout: 180000
# invalid login attempts before the connection is cut
maxAuthAttempts: 3
# maximum allowed size of an individual message in bytes
maxMessageSize: 1048576
# - type: ws-text
# options:
# # url path websocket connections connect to
# urlPath: /deepstream-v3
# # the amount of milliseconds between each ping/heartbeat message
# heartbeatInterval: 30000
# # the amount of milliseconds that writes to sockets are buffered
# outgoingBufferTimeout: 0
# # the maximum amount of bytes to buffer before flushing, stops the client from large enough packages
# # to block its responsiveness
# maxBufferByteSize: 100000
# # Security
# # should the server log invalid auth data, defaults to false
# logInvalidAuthData: false
# # amount of time a connection can remain open while not being logged in
# unauthenticatedClientTimeout: 180000
# # invalid login attempts before the connection is cut
# maxAuthAttempts: 3
# # maximum allowed size of an individual message in bytes
# maxMessageSize: 1048576
# - type: ws-json
# options:
# # url path websocket connections connect to
# urlPath: /deepstream-json
# # the amount of milliseconds between each ping/heartbeat message
# heartbeatInterval: 30000
# # the amount of milliseconds that writes to sockets are buffered
# outgoingBufferTimeout: 0
# # the maximum amount of bytes to buffer before flushing, stops the client from large enough packages
# # to block its responsiveness
# maxBufferByteSize: 100000
# # Security
# # should the server log invalid auth data, defaults to false
# logInvalidAuthData: false
# # amount of time a connection can remain open while not being logged in
# unauthenticatedClientTimeout: 180000
# # invalid login attempts before the connection is cut
# maxAuthAttempts: 3
# # maximum allowed size of an individual message in bytes
# maxMessageSize: 1048576
- type: http
options:
# allow 'authData' parameter in POST requests, if disabled only token and OPEN auth is
# possible
allowAuthData: true
# path for POST requests
postPath: /api
# path for GET requests
getPath: /api
# should the server log invalid auth data, defaults to false
logInvalidAuthData: false
# http request timeout in milliseconds, defaults to 20000
requestTimeout: 20000
# - type: mqtt
# options:
# # port for the mqtt server
# port: 1883
# # host for the mqtt server
# host: 0.0.0.0
# # timeout for idle devices
# idleTimeout: 60000
# Logger Configuration
logger:
# use the default logger, this does not currently support meta objects
type: default
options:
colors: true
# log using json, this supports meta objects
# name: pino
# options:
# # this value will always overwrite value of logLevel (line 4)
# logLevel: 0
# name: winston
# options:
# transports:
# # specify a list of transports (console, file, time)
# -
# type: console
# options:
# level: verbose
# colorize: true
# -
# type: file
# level: debug
# options:
# filename: 'logs.json'
# -
# type: time
# level: warn
# options:
# filename: time-rotated-logfile
# datePattern: .yyyy-MM-dd-HH-mm
# cache:
# name: redis
# options:
# host: ${REDIS_HOST}
# port: ${REDIS_PORT}
# storage:
# name: mongodb
# options:
# connectionString: ${MONGO_CONNECTION_STRING}
# db: default
# Authentication
auth:
- type: none
# # reading users and passwords from the storage layer
# - type: storage
# options:
# # the table users are stored in storage
# table: Users
# # the split character used for tables (defaults to /)
# tableSplitChar: string
# # automatically create users if they don't exist in the database
# createUser: true
# # the name of a HMAC digest algorithm
# hash: 'md5'
# # the number of times the algorithm should be applied
# iterations: 100
# # the length of the resulting key
# # keyLength: 32
# - type: file
# options:
# # Path to the user file. Can be json, js or yml
# users: fileLoad(users.yml)
# # the name of a HMAC digest algorithm
# hash: 'md5'
# # the number of times the algorithm should be applied
# iterations: 100
# # the length of the resulting key
# keyLength: 32
# # getting permissions from a http webhook
# - type: http
# options:
# # a post request will be send to this url on every incoming connection
# endpointUrl: https://someurl.com/validateLogin
# # any of these will be treated as access granted
# permittedStatusCodes: [ 200 ]
# # if the webhook didn't respond after this amount of milliseconds, the connection will be rejected
# requestTimeout: 2000
# # promote the following items from the login auth data into headers
# promoteToHeader:
# - token
# # the codes which the auth handler should retry. This is useful for when the API you depend on is
# # flaky or going through a not so blue/green deployment
# retryStatusCodes: [ 404, 504 ]
# # the maximum amount of retries before returning a false login
# retryAttempts: 3
# # the time in milliseconds between retries
# retryInterval: 5000
# Permissioning
permission:
type: config
options:
# Permissions file
permissions: fileLoad(permissions.yml)
# Amount of times nested cross-references will be loaded. Avoids endless loops
maxRuleIterations: 3
# PermissionResults are cached to increase performance. Lower number means more loading
cacheEvacuationInterval: 60000
monitoring:
- type: none
# # Allows monitoring stats to be requested via HTTP, useful for polling agents
# # such as LogStash
# - type: http
# options:
# url: /monitoring
# allowOpenPermissions: false
# headerKey: deepstream-password2
# headerValue: deepstream-secret
# # Logs monitoring stats, useful for kibana where you can visualize meta data
# - type: log
# options:
# logInterval: 30000
# monitoringKey: DEEPSTREAM_MONITORING
# clusterNode:
# type: default
# options:
# host: localhost
# port: 6379
# Custom Plugins
# plugins:
# custom:
# path: '...'
# heap-snapshot:
# name: 'heap-snapshot'
# options:
# interval: 60000
# outputDir: file(../heap-snapshots)
# aws:
# name: aws
# options:
# accessKeyId: ${AWS_ACCESS_KEY}
# secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
# services:
# - type: s3-sync
# options:
# syncInterval: 60000
# syncDir: file(../heap-snapshots)
# bucketName: ${SYNC_BUCKET_NAME}
# bucketRegion: ${AWS_DEFAULT_REGION}
================================================
FILE: conf/permissions.yml
================================================
presence:
"*":
allow: true
record:
"*":
create: true
write: true
read: true
delete: true
listen: true
notify: true
event:
"*":
publish: true
subscribe: true
listen: true
rpc:
"*":
provide: true
request: true
================================================
FILE: conf/users.yml
================================================
# Username
userA:
# Password hash ( hash options passed within config.yml )
# This hash represents clear text "password" with default options
password: "rCOSZxJrgze2AZdVQh12c6ErDMOG0M+Rx5Yu7S5d91c=GS4SbTQYmoaGwjm2shEobg=="
# Server data is used within your permission handler
serverData:
someOptional: "auth-data"
# Client data is sent to the client on login
clientData:
favouriteColor: "red"
================================================
FILE: package.json
================================================
{
"name": "@deepstream/server",
"version": "10.0.0",
"description": "a scalable server for realtime webapps",
"main": "./dist/src/deepstream.io.js",
"bin": {
"deepstream": "./dist/bin/deepstream"
},
"engines": {
"node": ">=22.0.0"
},
"directories": {
"test": "test"
},
"pkg": {
"scripts": "./dist/src/config/*.js",
"assets": "./dist/ascii-logo.txt"
},
"mocha": {
"reporter": "dot",
"require": [
"ts-node/register/transpile-only",
"./src/test/common.ts"
],
"exit": true
},
"scripts": {
"start:inspect": "npm run tsc && node --inspect dist/bin/deepstream",
"start": "ts-node --transpile-only --project tsconfig.json --files ./bin/deepstream.ts start",
"tsc": "sh scripts/tsc.sh",
"license": "mkdir -p build && node scripts/license-aggregator > build/LICENSE && cat scripts/resources/missing-licenses.txt >> build/LICENSE",
"lint": "tslint --project .",
"lint:fix": "npm run lint -- --fix",
"test": "mocha 'src/**/*.spec.ts'",
"test:coverage": "nyc mocha 'src/**/*.spec.ts' && npm run test:coverage:combine",
"test:http-server": "node test/test-helper/start-test-server.js",
"e2e": "ts-node --transpile-only --project tsconfig.json --files ./node_modules/.bin/cucumber-js test-e2e --require './test-e2e/steps/**/*.ts' --exit",
"e2e:v3": "V3=true npm run e2e -- --tags \"not @V4\"",
"e2e:uws": "uws=true npm run e2e",
"e2e:uws:v3": "uws=true V3=true npm run e2e -- --tags \"not @V4\"",
"e2e:rpc": "npm run e2e -- --tags \"@rpcs\"",
"e2e:event": "npm run e2e -- --tags \"@events\"",
"e2e:record": "npm run e2e -- --tags \"@records\"",
"e2e:login": "npm run e2e -- --tags \"@login\"",
"e2e:presence": "npm run e2e -- --tags \"@presence\"",
"e2e:http": "npm run e2e -- --tags \"@http\"",
"e2e:coverage": "nyc cucumber-js test-e2e --require './test-e2e/steps/**/*.ts' --exit && npm run test:coverage:combine",
"test:all:coverage": "rm -rf .nyc_combined_coverage .nyc_output && npm run test:coverage && npm run e2e:coverage && nyc report --reporter=lcov -t .nyc_combined_coverage",
"test:coverage:combine": "rm -rf .nyc_output/processinfo && mkdir -p .nyc_combined_coverage && mv -f .nyc_output/* .nyc_combined_coverage/"
},
"repository": {
"type": "git",
"url": "https://github.com/deepstreamIO/deepstream.io.git"
},
"dependencies": {
"@deepstream/protobuf": "^1.0.8",
"@deepstream/types": "^2.3.2",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1",
"better-ajv-errors": "^1.2.0",
"body-parser": "^2.2.0",
"chalk": "^4.1.2",
"commander": "^11.1.0",
"content-type": "^1.0.5",
"glob": "^8.1.0",
"http-shutdown": "^1.2.2",
"http-status": "^1.7.0",
"js-yaml": "^4.1.0",
"mqtt-connection": "^4.1.0",
"needle": "^3.2.0",
"pino": "^9.6.0",
"source-map-support": "^0.5.21",
"uuid": "^8.3.2",
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.51.0",
"ws": "^7.5.9"
},
"devDependencies": {
"@deepstream/client": "^7.0.4",
"@types/body-parser": "^1.19.3",
"@types/content-type": "^1.1.6",
"@types/cucumber": "^6.0.1",
"@types/glob": "^8.1.0",
"@types/js-yaml": "^4.0.7",
"@types/mkdirp": "^1.0.1",
"@types/mocha": "^8.0.4",
"@types/needle": "^3.2.1",
"@types/node": "^14.18.63",
"@types/sinon": "^10.0.19",
"@types/sinon-chai": "^3.2.10",
"@types/uuid": "^8.3.4",
"@types/ws": "^7.4.7",
"@yao-pkg/pkg": "^6.4.0",
"async": "^3.2.4",
"chai": "^4.3.10",
"coveralls": "^3.1.1",
"cucumber": "^6.0.7",
"deepstream.io-client-js": "^2.3.4",
"husky": "^4.3.8",
"istanbul": "^0.4.5",
"mocha": "^10.2.0",
"n0p3": "^1.0.2",
"nyc": "^15.1.0",
"proxyquire": "^2.1.3",
"sinon": "^16.1.0",
"sinon-chai": "^3.7.0",
"ts-essentials": "^10.0.4",
"ts-node": "^10.9.1",
"tslint": "^6.1.3",
"typescript": "^5.8.3"
},
"author": "deepstreamHub GmbH",
"license": "MIT",
"bugs": {
"url": "https://github.com/deepstreamIO/deepstream.io/issues"
},
"homepage": "https://deepstreamio.github.io/",
"husky": {
"hooks": {
"pre-commit": "npm run lint && npm run tsc",
"pre-push": "npm run tsc && npm t && npm run e2e -- --fail-fast && npm run e2e:uws -- --fail-fast && bash scripts/package.sh true true && node scripts/node-test.js && node scripts/executable-test.js",
"pre-publish": "npm run tsc"
}
},
"nyc": {
"include": [
"src/**/*.ts"
],
"exclude": [
"src/**/*.spec.ts",
"src/connection-endpoint/json/*",
"src/connection-endpoint/mqtt/*",
"src/connection-endpoint/text/*"
],
"extension": [
".ts"
],
"require": [
"ts-node/register/transpile-only"
],
"reporter": [
"lcov"
],
"sourceMap": true,
"instrument": true
}
}
================================================
FILE: scripts/connector/package-connector.sh
================================================
#!/bin/bash
PACKAGED_NODE_VERSION="v10"
OS=$( node -e "console.log(require('os').platform())" )
NODE_VERSION=$( node --version )
COMMIT=$( git log --pretty=format:%h -n 1 )
PACKAGE_VERSION=$( cat package.json | grep version | awk '{ print $2 }' | sed s/\"//g | sed s/,//g )
PACKAGE_NAME=$( cat package.json | grep name | awk '{ print $2 }' | sed s/\"//g | sed s/,//g )
PACKAGE_NAME=$( node -e "console.log(process.argv[1].replace('@deepstream/', 'deepstream.io-'))" $PACKAGE_NAME )
# These must happen before any exits otherwise deployment would fail
# Clean the build directory
rm -rf build
mkdir -p build/$PACKAGE_VERSION
if ! [[ $NODE_VERSION == $PACKAGED_NODE_VERSION* ]]; then
echo "Packaging only done on $PACKAGED_NODE_VERSION.x"
exit
fi
if [ $OS == "darwin" ]; then
PLATFORM="mac"
elif [ $OS == "linux" ]; then
PLATFORM="linux"
elif [ $OS == "win32" ]; then
PLATFORM="windows"
else
echo "Operating system $OS not supported for packaging"
exit
fi
FILE_NAME=$PACKAGE_NAME-$PLATFORM-$PACKAGE_VERSION-$COMMIT
# Do a git archive and a production install
# to have cleanest output
git archive --format=zip $COMMIT -o ./build/$PACKAGE_VERSION/temp.zip
cd ./build/$PACKAGE_VERSION
unzip temp.zip -d $PACKAGE_NAME
cd $PACKAGE_NAME
npm install
npm run tsc # Generate dist
rm -rf node_modules
npm install --omit=dev
echo 'Installed NPM Dependencies'
if [ $PLATFORM == 'mac' ]; then
FILE_NAME="$FILE_NAME.zip"
CLEAN_FILE_NAME="$PACKAGE_NAME-$PLATFORM.zip"
zip -r ../$FILE_NAME .
elif [ $PLATFORM == 'windows' ]; then
FILE_NAME="$FILE_NAME.zip"
CLEAN_FILE_NAME="$PACKAGE_NAME-$PLATFORM.zip"
7z a ../$FILE_NAME .
else
FILE_NAME="$FILE_NAME.tar.gz"
CLEAN_FILE_NAME="$PACKAGE_NAME-$PLATFORM.tar.gz"
tar czf ../$FILE_NAME .
fi
cd ..
rm -rf $PACKAGE_NAME temp.zip
cp $FILE_NAME ./$CLEAN_FILE_NAME
echo 'Done'
================================================
FILE: scripts/connector/test-connector.sh
================================================
#!/bin/bash
set -e
curl -o deepstream_package.json https://raw.githubusercontent.com/deepstreamIO/deepstream.io/master/package.json
DEEPSTREAM_VERSION="$( cat deepstream_package.json | grep version | awk '{ print $2 }' | sed s/\"//g | sed s/,//g )"
NODE_VERSION=$( node --version )
OS=$( node -e "console.log(require('os').platform())" )
PACKAGE_VERSION=$( cat package.json | grep version | awk '{ print $2 }' | sed s/\"//g | sed s/,//g )
PACKAGE_NAME=$( cat package.json | grep name | awk '{ print $2 }' | sed s/\"//g | sed s/,//g )
TYPE=$( node -e "console.log(process.argv[1].match('@deepstream/(.*)-(.*)')[1])" $PACKAGE_NAME )
CONNECTOR=$( node -e "console.log(process.argv[1].match('@deepstream/(.*)-(.*)')[2])" $PACKAGE_NAME )
rm -rf build
mkdir build
cd build
if [ -z $1 ]; then
if [[ -z ${TRAVIS_TAG} ]] && [[ -z ${APPVEYOR_REPO_TAG} ]]; then
echo "Only runs on tags"
exit
elif [[ ${APPVEYOR_REPO_TAG} = false ]]; then
echo "On appveyor, not a tag"
exit
else
echo "Running on tag ${TRAVIS_TAG} ${APPVEYOR_REPO_TAG}"
fi
else
echo "Build forced although not tag"
fi
echo "Starting deepstream.io $TYPE $CONNECTOR $PACKAGE_VERSION test for $DEEPSTREAM_VERSION on $OS"
echo "Downloading deepstream $DEEPSTREAM_VERSION"
if [ $OS = "win32" ]; then
DEEPSTREAM=deepstream.io-windows-${DEEPSTREAM_VERSION}
curl -o ${DEEPSTREAM}.zip -L https://github.com/deepstreamIO/deepstream.io/releases/download/v${DEEPSTREAM_VERSION}/${DEEPSTREAM}.zip
7z x ${DEEPSTREAM}.zip -o${DEEPSTREAM}
elif [ $OS == 'darwin' ]; then
DEEPSTREAM=deepstream.io-mac-${DEEPSTREAM_VERSION}
curl -o ${DEEPSTREAM}.zip -L https://github.com/deepstreamIO/deepstream.io/releases/download/v${DEEPSTREAM_VERSION}/${DEEPSTREAM}.zip
unzip ${DEEPSTREAM} -d ${DEEPSTREAM}
else
DEEPSTREAM=deepstream.io-linux-${DEEPSTREAM_VERSION}
mkdir -p ${DEEPSTREAM}
curl -o ${DEEPSTREAM}.tar.gz -L https://github.com/deepstreamIO/deepstream.io/releases/download/v${DEEPSTREAM_VERSION}/${DEEPSTREAM}.tar.gz
tar -xzf ${DEEPSTREAM}.tar.gz -C ${DEEPSTREAM}
fi
cd ${DEEPSTREAM}
chmod 555 deepstream
echo "./deepstream --version"
./deepstream --version
echo "./deepstream install $TYPE $CONNECTOR:$PACKAGE_VERSION"
./deepstream install $TYPE $CONNECTOR:$PACKAGE_VERSION --verbose
./deepstream start -c ../../example-config.yml -l ./lib &
PROC_ID=$!
sleep 10
if ! [ kill -0 "$PROC_ID" > /dev/null 2>&1 ]; then
echo "Deepstream is not running after the first ten seconds"
exit 1
fi
# Rest comes on beta.5
================================================
FILE: scripts/details.js
================================================
var exec = require( 'child_process' ).execSync;
var fs = require( 'fs' );
var path = require( 'path' );
var pkg = require( '../package' );
if( process.argv[2] === 'VERSION' ) {
console.log( pkg.version );
} else if( process.argv[2] === 'UWS_VERSION' ) {
console.log( pkg.dependencies["uWebSockets.js"].replace('^','') );
} else if( process.argv[2] === 'NAME' ) {
console.log( pkg.name );
} else if( process.argv[2] === 'OS' ) {
console.log( require( 'os' ).platform() );
} else if( process.argv[2] === 'COMMIT' ) {
console.log( exec( 'git log --pretty=format:%h -n 1' ).toString() );
} else if( process.argv[2] === 'META' ) {
writeMetaFile();
} else {
console.log( 'ERROR: Pass in VERSION or NAME as env variable' );
}
function writeMetaFile() {
var meta = {
deepstreamVersion: pkg.version,
gitRef: exec( 'git rev-parse HEAD' ).toString().trim(),
buildTime: new Date().toString()
};
fs.writeFileSync( path.join( __dirname, '..', 'dist', 'meta.json' ), JSON.stringify( meta, null, 2 ), 'utf8' );
}
================================================
FILE: scripts/executable-test.js
================================================
const { exec } = require('child_process')
exec('./build/deepstream info', (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`)
process.exit(1)
}
if (stderr) {
console.log(`stderr: ${stderr}`)
process.exit(1)
}
process.exit(0)
})
================================================
FILE: scripts/license-aggregator.js
================================================
#!/usr/bin/env node
const path = require('path')
const fs = require('fs')
const child_process = require('child_process')
const async = require('async')
const PRE_HEADER = fs.readFileSync('LICENSE', 'utf8')
const HEADER = `
This license applies to all parts of deepstream.io that are not externally
maintained libraries.
The externally maintained libraries used by deepstream.io are:
`
const emptyState = "see MISSING LICENSES at the bottom of this file"
if (path.basename(process.cwd()) === 'scripts') {
console.error('Run this script from the project root!')
process.exit(0)
}
child_process.execSync('npm list --omit=dev --json > licenses.json')
const mainModule = require('../licenses.json')
const moduleNames = []
traverseDependencies(mainModule)
function traverseDependencies(module) {
for (let dependency in module.dependencies) {
moduleNames.push(dependency)
traverseDependencies(module.dependencies[dependency])
}
}
// This source code is taken from the 'license-spelunker' npm module, it was patched
/*
The MIT License (MIT)
Copyright (c) 2013 Mike Brevoort
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var projPath = path.resolve(process.argv[2] || '.')
console.error('Project Path', projPath)
var topPkg = require(path.join(projPath, 'package.json'))
var modules = []
var count = 0
doLevel(projPath)
function doLevel(nodePath) {
var pkg = require(path.join(nodePath, 'package.json'))
if (topPkg.name !== pkg.name && moduleNames.indexOf(pkg.name) === -1) {
return
}
var nodeModulesPath = path.join(nodePath, 'node_modules')
count ++
//console.error('package.json license', pkg.license)
fs.exists(nodeModulesPath, function (dirExists) {
if (dirExists) {
fs.readdir(nodeModulesPath, function (err, files) {
if (err) throw err
files = files.map(function (f) { return path.join(nodeModulesPath, f) })
async.filter(files, isModuleDirectory, (err, directories) => {
directories.forEach(doLevel)
})
})
}
})
licenseText(nodePath, function (license) {
var licenceProperty = pkg.license || pkg.licenses
var licenceUrl = (pkg.license || {}).url
if ((licenceProperty || {}).type) {
licenceProperty = licenceProperty.type
licenceUrl = licenceProperty[0].url
}
if (((licenceProperty || {})[0] || []).type) {
licenceProperty = licenceProperty[0].type
licenceUrl = licenceProperty[0].url
}
if (pkg.name !== topPkg.name) {
modules.push({
name: pkg.name,
version: pkg.version,
url: 'http://npmjs.org/package/' + pkg.name,
localPath: path.relative(projPath,nodePath),
pkgLicense: licenceProperty,
licenceUrl: licenceUrl,
license: license
})
}
count--
if (count == 0) {
var noLicenseFile = modules.filter(function (m) { return m.license === emptyState })
var andNoPkgJsonLicense = noLicenseFile.filter(function (m) { return !m.pkgLicense })
// Status report
// Write to StdErr
console.error('LICENSE FILE REPORT FOR ', topPkg.name)
console.error(modules.length + ' nested dependencies')
console.error(noLicenseFile.length + ' without identifiable license text')
console.error(andNoPkgJsonLicense.length + ' without even a package.json license declaration', '\n\n')
// Write to StdOut
console.log(PRE_HEADER)
console.log('')
console.log(HEADER)
modules.forEach(function(m) {
console.log((modules.indexOf(m)+1) + ' ----------------------------------------------------------------------------')
console.log(m.name + '@' + m.version)
console.log(m.url)
console.log(m.localPath)
if (m.pkgLicense) console.log('From package.json license property:', JSON.stringify(m.pkgLicense))
if (m.licenceUrl) console.log('From package.json url property:', JSON.stringify(m.licenceUrl))
console.log('')
console.log(m.license)
console.log('')
})
}
})
}
function licenseText (nodePath, cb) {
var possibleLicensePaths = [
path.join(nodePath, 'LICENSE'),
path.join(nodePath, 'LICENCE'),
path.join(nodePath, 'LICENSE.md'),
path.join(nodePath, 'LICENSE.txt'),
path.join(nodePath, 'LICENSE-MIT'),
path.join(nodePath, 'LICENSE-BSD'),
path.join(nodePath, 'LICENSE.BSD'),
path.join(nodePath, 'MIT-LICENSE.txt'),
path.join(nodePath, 'Readme.md'),
path.join(nodePath, 'README.md'),
path.join(nodePath, 'README.markdown')
]
async.reduceRight(possibleLicensePaths, emptyState, function (state, licensePath, reduceCb) {
var isAReadme = (licensePath.toLowerCase().indexOf('/readme') > 0)
// if we already found a licnese, don't bother looking at READMEs
if (state !== emptyState && isAReadme) return reduceCb (null, state)
fs.exists(licensePath, function (exists) {
if (!exists) return reduceCb(null, state)
fs.readFile(licensePath, { encoding: 'utf8' }, function (err, text) {
if (err) return logError(err, reduceCb)(err, state)
if (isAReadme) {
var match = text.match(/\n[# ]*license[ \t]*\n/i)
if (match) {
//console.log(match.input.substring(match.index))
return reduceCb (null, 'FROM README:\n' + match.input.substring(match.index))
}
else {
return reduceCb(null, state)
}
}
else {
return reduceCb (null, text)
}
return reduceCb (null, text)
})
})
}, function (err, license) {
if (err) return cb('ERROR FINDING LICENSE FILE ' + err )
cb (license)
})
}
function isModuleDirectory (dirPath, cb) {
var pkgPath = path.join(dirPath, 'package.json')
fs.stat(dirPath, function (err, stat) {
if (err) return logError(err, cb)(false)
var isdir = stat.isDirectory()
if (isdir) {
fs.access(pkgPath, (err) => {
cb(null, !err)
})
}
else {
cb(false)
}
})
}
function logError(err, cb) {
console.error('ERROR', err)
return cb
}
================================================
FILE: scripts/linux-package.sh
================================================
#!/bin/bash
set -e
if [[ -z $1 ]]; then echo "First param is distro ( centos | debian | ubuntu | ... )"; exit 1; fi
if [[ -z $2 ]]; then echo "Second param is version ( bionic | 7 | ... )"; exit 1; fi
if [[ -z $3 ]]; then
echo "No distribution version provided, so using the version from package.json"
curl -O https://raw.githubusercontent.com/deepstreamIO/deepstream.io/master/package.json
VERSION="$( cat package.json | grep version | awk '{ print $2 }' | sed s/\"//g | sed s/,//g )"
else
VERSION="$3"
fi
DISTRO=$1
DISTRO_NAME=$2
GIT_TAG_NAME=v${VERSION}
# RPM does not support dashes in versions
RPM_PACKAGE_VERSION=$( sed "s/-/_/" <<< ${VERSION} )
if [[ ${DISTRO} = "ubuntu" ]] || [[ ${DISTRO} = "debian" ]]; then
ENV="deb"
elif [[ ${DISTRO} = "centos" ]] || [[ ${DISTRO} = "fedora" ]]; then
ENV="rpm"
else
echo "Unsupported distro: $DISTRO"
exit 1;
fi
mkdir -p build
cd build
if [[ ${DISTRO} = 'centos' ]]; then
cat >Dockerfile <<EOF
FROM centos/devtoolset-7-toolchain-centos7
USER root
RUN yum install -y centos-release-scl
ENV BUILD_NODE=true
EOF
else
cat >Dockerfile <<EOF
FROM ${DISTRO}:${DISTRO_NAME}
EOF
fi
if [[ ${ENV} = 'deb' ]]; then
cat >>Dockerfile <<EOF
RUN apt-get update
RUN apt-get install -y curl build-essential git ruby ruby-dev rpm
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -
RUN apt-get install -y nodejs
EOF
else
cat >>Dockerfile <<EOF
RUN yum update -y
RUN yum install -y git curl rpmbuild ruby ruby-devel rubygems rpm-build
RUN yum -y install gcc gcc-c++ make openssl-devel
RUN curl --silent --location https://rpm.nodesource.com/setup_18.x | bash -
RUN yum -y install nodejs
EOF
fi
if [[ ${DISTRO} = 'ubuntu' ]]; then
cat >>Dockerfile <<EOF
RUN apt-get install -y python python2.7
EOF
fi
cat >>Dockerfile <<EOF
RUN gem install fpm --conservative || echo "fpm install failed"
RUN echo "Start"
RUN git config --global http.sslverify false
RUN git clone https://github.com/deepstreamio/deepstream.io.git
WORKDIR deepstream.io
RUN mkdir build
RUN git checkout tags/${GIT_TAG_NAME}
RUN npm install
RUN chmod 555 scripts/package.sh
RUN rm scripts/package.sh
RUN curl -s -L https://raw.githubusercontent.com/deepstreamIO/deepstream.io/master/scripts/package.sh -o scripts/package.sh
RUN chmod 555 scripts/package.sh
RUN ./scripts/package.sh true
EOF
if [[ $ENV = 'deb' ]]; then
cat >>Dockerfile <<EOF
RUN curl \
-T "build/deepstream.io_${VERSION}_amd64.deb" \
-H "X-Bintray-Publish:1" \
-H "X-Bintray-Debian-Distribution:${DISTRO_NAME}" \
-H "X-Bintray-Debian-Component:main" \
-H "X-Bintray-Debian-Architecture:amd64" \
-u yasserf:${BINTRAY_API_KEY} \
"https://api.bintray.com/content/deepstreamio/deb/deepstream.io/${GIT_TAG_NAME}/deepstream.io_${DISTRO_NAME}_${GIT_TAG_NAME}_amd64.deb"
EOF
fi
if [[ ${ENV} = 'rpm' ]]; then
cat >>Dockerfile <<EOF
RUN curl \
-T "build/deepstream.io-${RPM_PACKAGE_VERSION}-1.x86_64.rpm" \
-H "X-Bintray-Publish:1" \
-u "yasserf:${BINTRAY_API_KEY}" \
"https://api.bintray.com/content/deepstreamio/rpm/deepstream.io/${GIT_TAG_NAME}/deepstream.io-${DISTRO_NAME}-${VERSION}-1.x86_64.rpm"
EOF
fi
echo "Using Dockerfile:"
sed -e 's@^@ @g' Dockerfile
TAG="${GIT_TAG_NAME}"
echo "Building Docker image ${TAG}"
docker build --no-cache --tag=${TAG} .
echo "Removing Dockerfile"
rm -f Dockerfile
CIDFILE="cidfile"
ARGS="--cidfile=$CIDFILE"
rm -f ${CIDFILE} # Cannot exist
echo "Running build"
docker run ${ARGS} ${TAG}
echo "Removing container"
docker rm "$(cat ${CIDFILE})" >/dev/null
rm -f "${CIDFILE}"
echo "Build successful"
================================================
FILE: scripts/linux-test.sh
================================================
#!/bin/bash
set -e
if [ -z $1 ]; then echo "First param is distro ( centos | debian | ubuntu | ... )"; exit 1; fi
if [ -z $2 ]; then echo "Second param is version ( wheezy | 7 | ... )"; exit 1; fi
if [ -z $3 ]; then
echo "No distribution version provided, so using the version from package.json"
curl -o package.json https://raw.githubusercontent.com/deepstreamIO/deepstream.io/master/package.json
VERSION="$( cat package.json | grep version | awk '{ print $2 }' | sed s/\"//g | sed s/,//g )"
else
VERSION="$3"
fi
DISTRO=$1
DISTRO_NAME=$2
GIT_TAG_NAME=v$VERSION
if [ $DISTRO = "ubuntu" ] || [ $DISTRO = "debian" ]; then
ENV="deb"
elif [ $DISTRO = "centos" ]; then
ENV="rpm"
else
echo "Unsupported distro: $DISTRO"
exit 1;
fi
cat >Dockerfile <<EOF
FROM $DISTRO:$DISTRO_NAME
EOF
if [ $ENV = 'deb' ]; then
cat >>Dockerfile <<EOF
RUN echo "deb http://dl.bintray.com/deepstreamio/deb $DISTRO_NAME main" | tee -a /etc/apt/sources.list
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 379CE192D401AB61
RUN apt-get update
RUN apt-get install -y deepstream.io
EOF
else
cat >>Dockerfile <<EOF
RUN yum install -y wget
RUN wget https://bintray.com/deepstreamio/rpm/rpm -O /etc/yum.repos.d/bintray-deepstreamio-rpm.repo
RUN yum install -y deepstream.io
EOF
fi
cat >>Dockerfile <<EOF
RUN deepstream --version > version
RUN cat version
RUN grep -q ^$VERSION version
RUN deepstream install connector publishingtest
EOF
echo "Using Dockerfile:"
sed -e 's@^@ @g' Dockerfile
TAG="$DEBIAN_NAME_$GIT_TAG_NAME"
echo "Building Docker image ${TAG}"
docker build --tag=${TAG} .
echo "Removing Dockerfile"
rm -f Dockerfile
CIDFILE="cidfile"
ARGS="--cidfile=${CIDFILE}"
rm -f ${CIDFILE} # Cannot exist
echo "Running build"
docker run ${ARGS} ${TAG}
echo "Removing container"
docker rm "$(cat ${CIDFILE})" >/dev/null
rm -f "${CIDFILE}"
echo "Build successful"
================================================
FILE: scripts/node-test.js
================================================
const { Deepstream } = require('../dist/src/deepstream.io')
const server = new Deepstream({})
server.start()
server.on('stopped', () => process.exit(0))
setTimeout(() => server.stop(), 2000)
================================================
FILE: scripts/package.sh
================================================
#!/bin/bash
set -e
LTS_VERSION="22"
NODE_VERSION=$( node --version )
NODE_VERSION_WITHOUT_V=$( echo ${NODE_VERSION} | cut -c2-10 )
COMMIT=$( node scripts/details.js COMMIT )
PACKAGE_VERSION=$( node scripts/details.js VERSION )
PACKAGE_NAME=$( node scripts/details.js NAME )
OS=$( node scripts/details.js OS )
UWS_VERSION=$( node scripts/details.js UWS_VERSION )
PACKAGE_DIR=build/${PACKAGE_VERSION}
DEEPSTREAM_PACKAGE=${PACKAGE_DIR}/deepstream.io
GIT_BRANCH=$( git rev-parse --abbrev-ref HEAD )
CREATE_DISTROS=false
EXECUTABLE_NAME="build/deepstream"
# Needed even for void builds for travis deploy to pass
mkdir -p build
if ! [[ ${NODE_VERSION_WITHOUT_V} == ${LTS_VERSION}* ]]; then
echo "Packaging only done on $LTS_VERSION.x"
exit
fi
if [[ -z $1 ]]; then
if ! [[ ${GIT_BRANCH} = 'master' ]]; then
echo "Running on branch ${GIT_BRANCH}"
else
echo "Running on master"
fi
fi
if [[ $2 ]]; then
echo 'Ignoring distros'
elif [[ ${OS} = "linux" ]]; then
CREATE_DISTROS=true
echo "Checking if FPM is installed"
fpm --version
fi
function compile {
echo "Starting deepstream.io packaging with Node.js $NODE_VERSION_WITHOUT_V"
rm -rf build
mkdir build
echo "Installing missing npm packages, just in case something changes"
npm i
echo "Transpiling"
npm run tsc
echo "Generate License File using unmodified npm packages"
./scripts/license-aggregator.js > build/DEPENDENCIES.LICENSE
echo "Generating meta.json"
node scripts/details.js META
# Creating package structure
rm -rf build/${PACKAGE_VERSION}
mkdir -p ${DEEPSTREAM_PACKAGE}
mkdir ${DEEPSTREAM_PACKAGE}/var
mkdir ${DEEPSTREAM_PACKAGE}/lib
mkdir ${DEEPSTREAM_PACKAGE}/doc
cd ${DEEPSTREAM_PACKAGE}/lib
echo '{ "name": "TEMP" }' > package.json
echo "Adding uWebSockets.js to libs"
npm install --omit=dev --install-strategy=shallow uWebSockets.js@${UWS_VERSION}
echo "Adding cache plugins"
npm install --omit=dev --install-strategy=shallow \
@deepstream/cache-redis \
@deepstream/cache-memcached \
# @deepstream/cache-hazelcast
echo "Adding cluster plugins"
npm install --omit=dev --install-strategy=shallow \
@deepstream/clusternode-redis
echo "Adding storage plugins"
npm install --omit=dev --install-strategy=shallow \
@deepstream/storage-mongodb \
@deepstream/storage-rethinkdb \
@deepstream/storage-elasticsearch \
@deepstream/storage-postgres
echo "Adding logger plugins"
npm install --omit=dev --install-strategy=shallow \
@deepstream/logger-winston
mv node_modules/* .
rm -rf node_modules package.json
cd -
echo "Creating '$EXECUTABLE_NAME', this will take a while..."
LTS=${LTS_VERSION} OS=${OS} EXECUTABLE_NAME=${EXECUTABLE_NAME} node scripts/pkg.js
PROC_ID=$!
SECONDS=0;
while kill -0 "$PROC_ID" >/dev/null 2>&1; do
echo -ne "\rCompiling deepstream... ($SECONDS)"
sleep 10
done
echo ""
if wait ${pid}; then
echo -e "\tPkg Build Succeeded"
else
echo -e "\tPkg Build Failed"
exit 1
fi
echo "Adding docs"
echo -e "\tAdding Readme"
echo "Documentation is available at https://deepstreamhub.com/open-source
" > ${DEEPSTREAM_PACKAGE}/doc/README
echo -e "\tAdding Changelog"
cp CHANGELOG.md ${DEEPSTREAM_PACKAGE}/doc/CHANGELOG.md
echo -e "\tAdding Licenses"
curl -L https://raw.githubusercontent.com/nodejs/node/v22.x/LICENSE -o ${DEEPSTREAM_PACKAGE}/doc/NODE.LICENSE
mv build/DEPENDENCIES.LICENSE ${DEEPSTREAM_PACKAGE}/doc/LICENSE
echo "Moving deepstream into package structure at $DEEPSTREAM_PACKAGE"
cp -r conf ${DEEPSTREAM_PACKAGE}/
cp build/deepstream ${DEEPSTREAM_PACKAGE}/
echo "Patching config file for zip lib and var directories"
cp -f ./conf/config.yml ${DEEPSTREAM_PACKAGE}/conf/config.yml
if [[ ${OS} = "darwin" ]]; then
sed -i '' 's@#libDir: ../lib@libDir: ../lib@' ${DEEPSTREAM_PACKAGE}/conf/config.yml
else
sed -i 's@#libDir: ../lib@libDir: ../lib@' ${DEEPSTREAM_PACKAGE}/conf/config.yml
fi
}
function windows {
COMMIT_NAME="deepstream.io-windows-$PACKAGE_VERSION-$COMMIT.zip "
CLEAN_NAME="deepstream.io-windows-$PACKAGE_VERSION.zip"
echo "OS is windows"
echo -e "\tCreating zip deepstream.io-windows-$PACKAGE_VERSION.zip"
cd ${DEEPSTREAM_PACKAGE}
7z a ../${COMMIT_NAME} . > /dev/null
cp ../${COMMIT_NAME} ../${CLEAN_NAME}
cd -
}
function mac {
COMMIT_NAME="deepstream.io-mac-${PACKAGE_VERSION}-${COMMIT}"
CLEAN_NAME="deepstream.io-mac-${PACKAGE_VERSION}"
echo "OS is mac"
echo -e "\tCreating ${CLEAN_NAME}"
cd ${DEEPSTREAM_PACKAGE}
zip -r ../${COMMIT_NAME}.zip .
cp ../${COMMIT_NAME}.zip ../${CLEAN_NAME}.zip
cd -
rm -rf build/osxpkg
mkdir -p build/osxpkg/bin
mkdir -p build/osxpkg/etc/deepstream
mkdir -p build/osxpkg/lib/deepstream
mkdir -p build/osxpkg/share/doc/deepstream
mkdir -p build/osxpkg/var/log/deepstream
cp -r ${DEEPSTREAM_PACKAGE}/deepstream build/osxpkg/bin/deepstream
cp -r ${DEEPSTREAM_PACKAGE}/conf/* build/osxpkg/etc/deepstream
cp -r ${DEEPSTREAM_PACKAGE}/lib/* build/osxpkg/lib/deepstream
cp -r ${DEEPSTREAM_PACKAGE}/doc/* build/osxpkg/share/doc/deepstream
echo "Patching config file for lib and var directories"
sed -i '' 's@ ../lib@ /usr/local/lib/deepstream@' build/osxpkg/etc/deepstream/config.yml
sed -i '' 's@ ../var@ /usr/local/var/log/deepstream@' build/osxpkg/etc/deepstream/config.yml
cp build/osxpkg/etc/deepstream/config.yml build/osxpkg/etc/deepstream/config.defaults
chmod -R 777 build/osxpkg/bin
chmod -R 777 build/osxpkg/share
chmod -R 777 build/osxpkg/var
chmod -R 777 build/osxpkg/lib
chmod -R 777 build/osxpkg/etc
echo "\tCreating *.pkg"
pkgbuild \
--root build/osxpkg \
--identifier deepstream.io \
--version ${PACKAGE_VERSION} \
--info scripts/resources/PackageInfo \
--install-location /usr/local \
${DEEPSTREAM_PACKAGE}/../${COMMIT_NAME}.pkg
cp \
${DEEPSTREAM_PACKAGE}/../${COMMIT_NAME}.pkg \
${DEEPSTREAM_PACKAGE}/../${CLEAN_NAME}.pkg
rm -rf build/osxpkg
}
function linux {
echo "OS is linux"
echo -e "\tCreating tar.gz"
COMMIT_NAME="deepstream.io-linux-${PACKAGE_VERSION}-${COMMIT}.tar.gz"
CLEAN_NAME="deepstream.io-linux-${PACKAGE_VERSION}.tar.gz"
cd ${DEEPSTREAM_PACKAGE}
tar czf ../${COMMIT_NAME} .
cp ../${COMMIT_NAME} ../${CLEAN_NAME}
cd -
}
function distros {
echo -e "\tPatching config file for linux distros..."
if [[ ${OS} = "darwin" ]]; then
sed -i '' 's@ ../lib@ /var/lib/deepstream@' ${DEEPSTREAM_PACKAGE}/conf/config.yml
sed -i '' 's@ ../var@ /var/log/deepstream@' ${DEEPSTREAM_PACKAGE}/conf/config.yml
else
sed -i 's@ ../lib@ /var/lib/deepstream@' ${DEEPSTREAM_PACKAGE}/conf/config.yml
sed -i 's@ ../var@ /var/log/deepstream@' ${DEEPSTREAM_PACKAGE}/conf/config.yml
fi
echo -e "\t\tCreating rpm"
fpm \
-s dir \
-t rpm \
--package ./build/ \
--package-name-suffix ${COMMIT} \
-n deepstream.io \
-v ${PACKAGE_VERSION} \
--license "MIT" \
--vendor "deepstreamHub GmbH" \
--description "deepstream.io rpm package" \
--url https://deepstream.io/ \
-m "<info@deepstreamhub.com>" \
--after-install ./scripts/resources/daemon/after-install \
--before-remove ./scripts/resources/daemon/before-remove \
--before-upgrade ./scripts/resources/daemon/before-upgrade \
--after-upgrade ./scripts/resources/daemon/after-upgrade \
-f \
${DEEPSTREAM_PACKAGE}/doc/=/usr/share/doc/deepstream/ \
${DEEPSTREAM_PACKAGE}/conf/=/etc/deepstream/conf.d/ \
${DEEPSTREAM_PACKAGE}/lib/=/var/lib/deepstream/ \
./build/deepstream=/usr/bin/deepstream
echo -e "\t\tCreating deb"
fpm \
-s dir \
-t deb \
--package ./build \
--package-name-suffix ${COMMIT} \
-n deepstream.io \
-v ${PACKAGE_VERSION} \
--license "MIT" \
--vendor "deepstreamHub GmbH" \
--description "deepstream.io deb package" \
--url https://deepstream.io/ \
-m "<info@deepstreamhub.com>" \
--after-install ./scripts/resources/daemon/after-install \
--before-remove ./scripts/resources/daemon/before-remove \
--before-upgrade ./scripts/resources/daemon/before-upgrade \
--after-upgrade ./scripts/resources/daemon/after-upgrade \
-f \
--deb-no-default-config-files \
${DEEPSTREAM_PACKAGE}/doc/=/usr/share/doc/deepstream/ \
${DEEPSTREAM_PACKAGE}/conf/=/etc/deepstream/conf.d/ \
${DEEPSTREAM_PACKAGE}/lib/=/var/lib/deepstream/ \
./build/deepstream=/usr/bin/deepstream
}
function clean {
rm -rf ${DEEPSTREAM_PACKAGE}
}
compile
if [[ $OS = "win32" ]]; then
windows
elif [[ ${OS} = "darwin" ]]; then
mac
elif [[ ${OS} = "linux" ]]; then
linux
if [[ ${CREATE_DISTROS} = true ]]; then
distros
fi
fi
clean
echo "Files in build directory are $( ls build/ )"
echo "Done"
================================================
FILE: scripts/pkg.js
================================================
const { exec } = require('@yao-pkg/pkg')
const LTS = process.env.LTS
let OS = process.env.OS
if (OS === 'win32') {
OS = 'win'
}
if (OS === 'darwin') {
OS = 'macos'
}
const target = 'node'+ LTS + '-' + OS
exec(
[
'package.json',
'--targets',
target,
'--output',
process.env.EXECUTABLE_NAME,
'--options',
'--max-old-space-size=8192',
'--compress',
'GZip'
]).then(() => {
console.log('success')
})
================================================
FILE: scripts/release.sh
================================================
if [ -z $1 ]; then
echo "Please provide a release version: patch, minor or major"
exit
fi
if [ $( npm whoami ) != "deepstreamio" ]; then
echo "Please verify you can log into npm as deepstreamio before trying to release"
exit
fi
echo 'Starting release'
npm version $1
echo "Version now: $( node scripts/details.js VERSION )"
echo 'Pushing to github'
git push --follow-tags
echo "Now we wait for the CI to build and upload artifacts to release"
================================================
FILE: scripts/resources/PackageInfo
================================================
<?xml version="1.0"?>
<pkg-info auth="none">
</pkg-info>
================================================
FILE: scripts/resources/daemon/after-install
================================================
cp /etc/deepstream/conf.d/* /etc/deepstream/
mkdir -p /var/run/deepstream
mkdir -p /var/log/deepstream
mkdir -p /var/lib/deepstream
chmod -R 777 /var/run/deepstream
chmod -R 777 /var/log/deepstream
chmod -R 777 /var/lib/deepstream
chmod -R 777 /etc/deepstream
================================================
FILE: scripts/resources/daemon/after-upgrade
================================================
================================================
FILE: scripts/resources/daemon/before-remove
================================================
deepstream stop
================================================
FILE: scripts/resources/daemon/before-upgrade
================================================
cd /var/lib/deepstream
rm -rf deepstream.io-logger-winston*
rm -rf /etc/deepstream/conf.d
================================================
FILE: scripts/resources/missing-licenses.txt
================================================
----------------------------------------------------------------------------
MISSING LICENSES
----------------------------------------------------------------------------
adm-zip@0.4.7
http://npmjs.org/package/adm-zip
node_modules/adm-zip
From package.json license property: "MIT"
Copyright (c) 2012 Another-D-Mention Software and other contributors,
http://www.another-d-mention.ro/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------------
================================================
FILE: scripts/resources/node.rc
================================================
#include "winresrc.h"
#include "node_version.h"
// Application icon
1 ICON deepstream.ico
// Version resource
VS_VERSION_INFO VERSIONINFO
FILEVERSION NODE_MAJOR_VERSION,NODE_MINOR_VERSION,NODE_PATCH_VERSION,0
PRODUCTVERSION NODE_MAJOR_VERSION,NODE_MINOR_VERSION,NODE_PATCH_VERSION,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
# ifdef NODE_VERSION_IS_RELEASE
FILEFLAGS 0x0L
# else
FILEFLAGS VS_FF_PRERELEASE
# endif
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "deepstreamHub GmbH"
VALUE "ProductName", "deepstream.io"
VALUE "FileDescription", "A Scalable Server for Realtime Applications"
VALUE "FileVersion", DEEPSTREAM_VERSION
VALUE "ProductVersion", DEEPSTREAM_VERSION
VALUE "OriginalFilename", "deepstream.exe"
VALUE "InternalName", "deepstream"
VALUE "LegalCopyright", "Apache License 2.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
================================================
FILE: scripts/sanity-test.sh
================================================
#!/bin/bash
set -e
if [[ $1 == "deb" ]]; then
source /etc/lsb-release && echo "deb http://dl.bintray.com/deepstreamio/deb ${DISTRIB_CODENAME} main" | sudo tee -a /etc/apt/sources.list
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 379CE192D401AB61
sudo apt-get update
sudo apt-get install -y deepstream.io
elif [[ $1 == "rpm" ]]; then
sudo yum install -y wget
sudo wget https://bintray.com/deepstreamio/rpm/rpm -O /etc/yum.repos.d/bintray-deepstreamio-rpm.repo
sudo yum install -y deepstream.io
elif [[ $1 == "tar" ]]; then
if [[ -z $2 ]]; then
echo 'Missing version number when testing tar release'
exit 1
fi
curl -OL https://github.com/deepstreamIO/deepstream.io/releases/download/v$2/deepstream.io-linux-$2.tar.gz
tar xf deepstream.io-linux-$2.tar.gz
elif [[ $1 == "installed" ]]; then
echo "Assuming deepstream installed"
else
echo "use deb/rpm/tar/installed"
exit 1
fi
sudo deepstream service add
sudo deepstream service start
sudo deepstream service status
sleep 2
curl localhost:6020/health-check
if [[ $? == 1 ]]; then
echo 'Deepstream service not running';
exit 1;
fi
sudo deepstream service stop
sudo deepstream service remove
================================================
FILE: scripts/setup.sh
================================================
git clone https://github.com/deepstreamIO/deepstream.io.git
cd deepstream.io
sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules
git submodule update --init --recursive
npm i
npm run e2e:v3
================================================
FILE: scripts/trigger-build.sh
================================================
if [ -z $1 ]; then
echo "Missing branch name as first arguments"
exit 1
fi
body="{
\"request\": {
\"branch\":\"$1\",
\"message\": \"Tag ${TRAVIS_TAG}\"
}}"
echo $body
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Travis-API-Version: 3" \
-H "Authorization: token ${TRAVIS_TOKEN}" \
-d "$body" \
https://api.travis-ci.org/repo/deepstreamIO%2Fdeepstream.io/requests
================================================
FILE: scripts/tsc.sh
================================================
#!/usr/bin/env bash
rm -rf dist
./node_modules/.bin/tsc
cp ./ascii-logo.txt ./dist/ascii-logo.txt
cp ./package.json ./dist/package.json
cp ./package-lock.json ./dist/package-lock.json
cp -r conf ./dist/conf
cp ./dist/bin/deepstream.js ./dist/bin/deepstream
cp Dockerfile ./dist/Dockerfile
chmod +x ./dist/bin/deepstream
================================================
FILE: src/config/config-initialiser.spec.ts
================================================
import { expect } from 'chai'
import * as path from 'path'
import * as defaultConfig from '../default-options'
import * as configInitialiser from './config-initialiser'
import { EventEmitter } from 'events'
import { LOG_LEVEL } from '@deepstream/types'
describe('config-initializer', () => {
before(() => {
global.deepstreamConfDir = null
global.deepstreamLibDir = null
global.deepstreamCLI = null
})
describe('plugins are initialized as per configuration', () => {
it('loads plugins from a relative path', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.plugins = {
custom: {
path: './src/test/mock/plugin-mock',
options: { some: 'options' }
}
} as any
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.plugins.custom.description).to.equal('mock-plugin')
})
it('loads plugins via module names', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.plugins = {
cache: {
path: 'n0p3',
options: {}
}
} as any
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.toString()).to.equal('[object Object]')
})
it('loads plugins from a relative path and lib dir', () => {
global.deepstreamLibDir = './src/test/mock'
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.plugins = {
mock: {
path: './plugin-mock',
options: { some: 'options' }
}
} as any
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.plugins.mock.description).to.equal('mock-plugin')
})
})
describe('translates shortcodes into paths', () => {
it('translates cache', () => {
global.deepstreamLibDir = '/foobar'
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.ERROR
let errored = false
config.plugins = {
cache: {
name: 'blablub'
}
} as any
try {
configInitialiser.initialize(new EventEmitter(), config)
} catch (e) {
errored = true
}
expect(errored).to.equal(true)
})
})
describe('creates the right authentication handler', () => {
before(() => {
global.deepstreamLibDir = './src/test/plugins'
})
it('works for authtype: none', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.auth = [{
type: 'none',
options: {}
}]
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.authentication.description).to.equal('Open Authentication')
})
it('works for authtype: user', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.auth = [{
type: 'file',
options: {
users: {}
}
}]
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.authentication.description).to.contain('File Authentication')
})
it('works for authtype: http', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.auth = [{
type: 'http',
options: {
endpointUrl: 'http://some-url.com',
permittedStatusCodes: [200],
requestTimeout: 2000,
retryAttempts: 2,
retryInterval: 50,
retryStatusCodes: [ 404 ]
}
}]
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.authentication.description).to.equal('http webhook to http://some-url.com')
})
it('fails for missing auth sections', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
delete config.auth
expect(() => {
configInitialiser.initialize(new EventEmitter(), config)
}).to.throw('No authentication type specified')
})
it('allows passing a custom authentication handler', async () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.auth = [{
path: '../mock/authentication-handler-mock',
options: {
hello: 'there'
}
}]
const result = configInitialiser.initialize(new EventEmitter(), config)
await result.services.authentication.whenReady()
})
it('tries to find a custom authentication handler from name', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.auth = [{
name: 'my-custom-auth-handler',
options: {}
}]
expect(() => {
configInitialiser.initialize(new EventEmitter(), config)
}).to.throw()
})
it('overrides with type "none" when disableAuth is set', () => {
global.deepstreamCLI = { disableAuth: true }
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.auth = [{
type: 'http',
options: {}
}]
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.authentication.description).to.equal('Open Authentication')
delete global.deepstreamCLI
})
})
describe('creates the permission service', () => {
it('creates the config permission service', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.permission = {
type: 'config',
options: {
path: './test-e2e/config/permissions-complex.json'
}
}
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.permission.description).to.contain('Valve Permissions')
})
it('allows passing a custom permission handler', async () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.permission = {
path: '../mock/permission-handler-mock',
options: {
hello: 'there'
}
}
const result = configInitialiser.initialize(new EventEmitter(), config)
await result.services.permission.whenReady()
})
it('tries to find a custom authentication handler from name', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.auth = [{
name: 'my-custom-perm-handler',
options: {}
}]
expect(() => {
configInitialiser.initialize(new EventEmitter(), config)
}).to.throw()
})
it('fails for missing permission configs', () => {
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
delete config.permission
expect(() => {
configInitialiser.initialize(new EventEmitter(), config)
}).to.throw('No permission type specified')
})
it('overrides with type "none" when disablePermissions is set', () => {
global.deepstreamCLI = { disablePermissions: true }
const config = defaultConfig.get()
config.logLevel = LOG_LEVEL.OFF
config.permission = {
type: 'config',
options: {}
}
const result = configInitialiser.initialize(new EventEmitter(), config)
expect(result.services.permission.description).to.equal('none')
delete global.deepstreamCLI
})
})
})
================================================
FILE: src/config/config-initialiser.ts
================================================
import { readFileSync } from 'fs'
import { join } from 'path'
import { EOL } from 'os'
import * as utils from '../utils/utils'
import * as fileUtils from './file-utils'
import { DeepstreamConfig, DeepstreamServices, DeepstreamConnectionEndpoint, PluginConfig, DeepstreamLogger, DeepstreamAuthentication, DeepstreamPermission, LOG_LEVEL, EVENT, DeepstreamMonitoring, DeepstreamAuthenticationCombiner, DeepstreamHTTPService, DeepstreamClusterNode } from '@deepstream/types'
import { DistributedClusterRegistry } from '../services/cluster-registry/distributed-cluster-registry'
import { SingleClusterNode } from '../services/cluster-node/single-cluster-node'
import { VerticalClusterNode } from '../services/cluster-node/vertical-cluster-node'
import { DefaultSubscriptionRegistryFactory } from '../services/subscription-registry/default-subscription-registry-factory'
import { HTTPConnectionEndpoint } from '../connection-endpoint/http/connection-endpoint'
import { CombineAuthentication } from '../services/authentication/combine/combine-authentication'
import { OpenAuthentication } from '../services/authentication/open/open-authentication'
import { ConfigPermission } from '../services/permission/valve/config-permission'
import { OpenPermission } from '../services/permission/open/open-permission'
import { WSBinaryConnectionEndpoint } from '../connection-endpoint/websocket/binary/connection-endpoint'
import { WSTextConnectionEndpoint } from '../connection-endpoint/websocket/text/connection-endpoint'
import { WSJSONConnectionEndpoint } from '../connection-endpoint/websocket/json/connection-endpoint'
import { MQTTConnectionEndpoint } from '../connection-endpoint/mqtt/connection-endpoint'
import { FileBasedAuthentication } from '../services/authentication/file/file-based-authentication'
import { StorageBasedAuthentication } from '../services/authentication/storage/storage-based-authentication'
import { HttpAuthentication } from '../services/authentication/http/http-authentication'
import { NoopStorage } from '../services/storage/noop-storage'
import { LocalCache } from '../services/cache/local-cache'
import { StdOutLogger } from '../services/logger/std/std-out-logger'
import { PinoLogger } from '../services/logger/pino/pino-logger'
import { DeepstreamIOTelemetry } from '../services/telemetry/deepstreamio-telemetry'
import { NoopMonitoring } from '../services/monitoring/noop-monitoring'
import { CombineMonitoring } from '../services/monitoring/combine-monitoring'
import { DistributedLockRegistry } from '../services/lock/distributed-lock-registry'
import { DistributedStateRegistryFactory } from '../services/cluster-state/distributed-state-registry-factory'
import { get as getDefaultOptions } from '../default-options'
import Deepstream from '../deepstream.io'
import { NodeHTTP } from '../services/http/node/node-http'
import HTTPMonitoring from '../services/monitoring/http/monitoring-http'
import LogMonitoring from '../services/monitoring/log/monitoring-log'
import { InitialLogs } from './js-yaml-loader'
import * as configValidator from './config-validator'
import HeapSnapshot from '../plugins/heap-snapshot/heap-snapshot'
let commandLineArguments: any
const customPlugins = new Map()
const defaultPlugins = new Map<keyof DeepstreamServices, any>([
['cache', LocalCache],
['storage', NoopStorage],
['logger', StdOutLogger],
['locks', DistributedLockRegistry],
['subscriptions', DefaultSubscriptionRegistryFactory],
['clusterRegistry', DistributedClusterRegistry],
['clusterStates', DistributedStateRegistryFactory],
['clusterNode', SingleClusterNode],
['httpService', NodeHTTP],
])
export const mergeConnectionOptions = function (config: any) {
if (config && config.connectionEndpoints) {
const defaultConfig = getDefaultOptions()
for (const connectionEndpoint of config.connectionEndpoints) {
const defaultPlugin = defaultConfig.connectionEndpoints.find((defaultEndpoint) => defaultEndpoint.type === connectionEndpoint.type)
if (defaultPlugin) {
connectionEndpoint.options = utils.merge(defaultPlugin.options, connectionEndpoint.options)
}
}
}
}
/**
* Registers plugins by name. Useful when wanting to include
* custom plugins in a binary
*/
export const registerPlugin = function (name: string, construct: Function) {
customPlugins.set(name, construct)
}
/**
* Takes a configuration object and instantiates functional properties.
* CLI arguments will be considered.
*/
export const initialize = function (deepstream: Deepstream, config: DeepstreamConfig, initialLogs: InitialLogs = []): { config: DeepstreamConfig, services: DeepstreamServices } {
configValidator.validate(config)
if (config.showLogo === true) {
const logo = readFileSync(join(__dirname, '..', '..', '/ascii-logo.txt'), 'utf8')
process.stdout.write(logo)
process.stdout.write(`${EOL}===================== starting =====================${EOL}`)
}
// @ts-ignore
commandLineArguments = global.deepstreamCLI || {}
handleUUIDProperty(config)
mergeConnectionOptions(config)
const services = {} as DeepstreamServices
services.notifyFatalException = () => {
if (config.exitOnFatalError) {
process.exit(1)
} else {
deepstream.emit(EVENT.FATAL_EXCEPTION)
}
}
services.logger = handleLogger(config, services)
services.monitoring = handleMonitoringPlugins(config, services)
initialLogs.forEach((log) => {
switch (log.level) {
case LOG_LEVEL.DEBUG:
services.logger.debug(log.event, log.message, log.meta)
break
case LOG_LEVEL.ERROR:
services.logger.error(log.event, log.message, log.meta)
break
case LOG_LEVEL.INFO:
services.logger.info(log.event, log.message, log.meta)
break
case LOG_LEVEL.WARN:
services.logger.warn(log.event, log.message, log.meta)
break
case LOG_LEVEL.FATAL:
services.logger.fatal(log.event, log.message, log.meta)
break
}
})
services.subscriptions = new (resolvePluginClass(config.subscriptions, 'subscriptions', services.logger))(config.subscriptions.options, services, config)
services.storage = new (resolvePluginClass(config.storage, 'storage', services.logger))(config.storage.options, services, config)
services.cache = new (resolvePluginClass(config.cache, 'cache', services.logger))(config.cache.options, services, config)
services.authentication = handleAuthStrategies(config, services)
services.permission = handlePermissionStrategies(config, services)
services.connectionEndpoints = handleConnectionEndpoints(config, services)
services.locks = new (resolvePluginClass(config.locks, 'locks', services.logger))(config.locks.options, services, config)
services.clusterNode = handleClusterNode(config, services)
services.clusterRegistry = new (resolvePluginClass(config.clusterRegistry, 'clusterRegistry', services.logger))(config.clusterRegistry.options, services, config)
services.clusterStates = new (resolvePluginClass(config.clusterStates, 'clusterStates', services.logger))(config.clusterStates.options, services, config)
services.httpService = handleHTTPServer(config, services)
services.telemetry = handleTelemetry(config, services)
handleCustomPlugins(config, services)
return { config, services }
}
/**
* Transform the UUID string config to a UUID in the config object.
*/
function handleUUIDProperty (config: DeepstreamConfig): void {
if (config.serverName === 'UUID') {
config.serverName = utils.getUid()
}
}
function handleClusterNode (config: DeepstreamConfig, services: any): DeepstreamClusterNode {
let ClusterNodeClass = defaultPlugins.get('clusterNode')
if (commandLineArguments.clusterSize) {
config.clusterNode.name = 'vertical'
}
if (config.clusterNode.name === 'vertical') {
ClusterNodeClass = VerticalClusterNode
} else if (config.clusterNode.name || config.clusterNode.path) {
ClusterNodeClass = resolvePluginClass(config.clusterNode, 'clusterNode', services.logger)
if (!ClusterNodeClass) {
throw new Error(`unable to resolve plugin ${config.clusterNode.name || config.clusterNode.path}`)
}
}
return new ClusterNodeClass(config.clusterNode.options, services, config)
}
/**
* Initialize the logger and overwrite the root logLevel if it's set
* CLI arguments will be considered.
*/
function handleLogger (config: DeepstreamConfig, services: DeepstreamServices): DeepstreamLogger {
const configOptions = (config.logger || {}).options
if (commandLineArguments.colors !== undefined) {
configOptions.colors = commandLineArguments.colors
}
let LoggerClass = defaultPlugins.get('logger')
if (config.logger.name === 'pino') {
LoggerClass = PinoLogger
} else if (config.logger.name || config.logger.path) {
LoggerClass = resolvePluginClass(config.logger, 'logger', services.logger)
if (!LoggerClass) {
throw new Error(`unable to resolve plugin ${config.logger.name || config.logger.path}`)
}
}
const logger = new LoggerClass(configOptions, services, config)
if (logger.log) {
logger.debug = logger.debug || logger.log.bind(logger, LOG_LEVEL.DEBUG)
logger.info = logger.info || logger.log.bind(logger, LOG_LEVEL.INFO)
logger.warn = logger.warn || logger.log.bind(logger, LOG_LEVEL.WARN)
logger.error = logger.error || logger.log.bind(logger, LOG_LEVEL.ERROR)
logger.fatal = logger.fatal || logger.log.bind(logger, LOG_LEVEL.FATAL)
}
if (commandLineArguments.logLevel !== undefined) {
configOptions.logLevel = commandLineArguments.logLevel
}
if (LOG_LEVEL[configOptions.logLevel] !== undefined) {
if (typeof configOptions.logLevel === 'string') {
logger.setLogLevel(LOG_LEVEL[configOptions.logLevel])
} else {
logger.setLogLevel(configOptions.logLevel)
}
} else if (configOptions.logLevel) {
throw new Error (`Unknown logLevel ${LOG_LEVEL[configOptions.logLevel]}`)
}
return logger
}
/**
* Handle the plugins property in the config object the connectors.
* Plugins can be passed either as a __path__ property or as a __name__ property with
* a naming convention: *{cache: {name: 'redis'}}* will be resolved to the
* npm module *@deepstream/cache-redis*
* Options to the constructor of the plugin can be passed as *options* object.
*
* CLI arguments will be considered.
*/
function handleCustomPlugins (config: DeepstreamConfig, services: any): void {
services.plugins = {}
if (config.plugins == null) {
return
}
const plugins = { ...config.plugins }
for (const key in plugins) {
const plugin = plugins[key]
if (plugin.name === 'heap-snapshot') {
services.plugins[key] = new HeapSnapshot(plugin.options || {}, services)
} else {
const PluginConstructor = resolvePluginClass(plugin, 'plugin', services.logger)
services.plugins[key] = new PluginConstructor(plugin.options || {}, services, config)
}
}
}
/**
* Handle connection endpoint plugin config.
* The type is typically the protocol e.g. ws
* Plugins can be passed either as a __path__ property or as a __name__ property with
* a naming convetion: *{amqp: {name: 'my-plugin'}}* will be resolved to the
* npm module *deepstream.io/connection-my-plugin*
* Exception: the name *uws* will be resolved to deepstream.io's internal uWebSockets plugin
* Options to the constructor of the plugin can be passed as *options* object.
*
* CLI arguments will be considered.
*/
function handleConnectionEndpoints (config: DeepstreamConfig, services: any): DeepstreamConnectionEndpoint[] {
// delete any endpoints that have been set to `null`
for (const type in config.connectionEndpoints) {
if (config.connectionEndpoints[type] === null) {
delete config.connectionEndpoints[type]
}
}
if (!config.connectionEndpoints || Object.keys(config.connectionEndpoints).length === 0) {
throw new Error('No connection endpoints configured')
}
const connectionEndpoints: DeepstreamConnectionEndpoint[] = []
for (const plugin of config.connectionEndpoints) {
plugin.options = plugin.options || {}
let PluginConstructor
if (plugin.type === 'ws-binary') {
PluginConstructor = WSBinaryConnectionEndpoint
} else if (plugin.type === 'ws-text') {
PluginConstructor = WSTextConnectionEndpoint
} else if (plugin.type === 'ws-json') {
PluginConstructor = WSJSONConnectionEndpoint
} else if (plugin.type === 'mqtt') {
PluginConstructor = MQTTConnectionEndpoint
} else if (plugin.type === 'http') {
PluginConstructor = HTTPConnectionEndpoint
} else {
PluginConstructor = resolvePluginClass(plugin, 'connection', services.logger)
}
connectionEndpoints.push(new PluginConstructor(plugin.options, services, config))
}
return connectionEndpoints
}
/**
* Instantiate the given plugin, which either needs a path property or a name
* property which fits to the npm module name convention. Options will be passed
* to the constructor.
*
* CLI arguments will be considered.
*/
function resolvePluginClass (plugin: PluginConfig, type: string, logger: DeepstreamLogger): any {
if (customPlugins.has(plugin.name)) {
return customPlugins.get(plugin.name)
}
// Required for bundling via nexe
const req = require
let requirePath
let pluginConstructor
let es6Adaptor
if (plugin.path != null) {
try {
requirePath = fileUtils.lookupLibRequirePath(plugin.path)
es6Adaptor = req(requirePath)
pluginConstructor = es6Adaptor.default ? es6Adaptor.default : es6Adaptor
} catch (error) {
logger.fatal(EVENT.CONFIG_ERROR, `Error loading ${type} plugin via path ${requirePath}: ${error}`)
// Throw error due to how tests are written
throw new Error()
}
} else if (plugin.name != null && type) {
try {
requirePath = fileUtils.lookupLibRequirePath(`@deepstream/${type.toLowerCase()}-${plugin.name.toLowerCase()}`)
es6Adaptor = req(requirePath)
} catch (firstError) {
const firstPath = requirePath
try {
requirePath = fileUtils.lookupLibRequirePath(`deepstream.io-${type.toLowerCase()}-${plugin.name.toLowerCase()}`)
es6Adaptor = req(requirePath)
} catch (secondError) {
logger.debug(EVENT.CONFIG_ERROR, `Error loading module ${firstPath}: ${firstError}`)
logger.debug(EVENT.CONFIG_ERROR, `Error loading module ${requirePath}: ${secondError}`)
logger.fatal(EVENT.CONFIG_ERROR, 'Error loading module, exiting')
// Throw error due to how tests are written
throw new Error()
}
}
pluginConstructor = es6Adaptor.default ? es6Adaptor.default : es6Adaptor
} else if (plugin.name != null) {
try {
requirePath = fileUtils.lookupLibRequirePath(plugin.name)
es6Adaptor = req(requirePath)
pluginConstructor = es6Adaptor.default ? es6Adaptor.default : es6Adaptor
} catch (error) {
logger.fatal(EVENT.CONFIG_ERROR, `Error loading ${type} plugin via name ${plugin.name}`)
// Throw error due to how tests are written
throw new Error()
}
} else if (plugin.type === 'default' && defaultPlugins.has(type as any)) {
pluginConstructor = defaultPlugins.get(type as any)
} else {
// This error is used to bubble the event due to how tests are written
throw new Error(`Neither name nor path property found for ${type} plugin type: ${plugin.type}`)
}
return pluginConstructor
}
/**
* Instantiates the authentication handlers registered for *config.auth.type*
*
* CLI arguments will be considered.
*/
function handleAuthStrategies (config: DeepstreamConfig, services: DeepstreamServices): DeepstreamAuthenticationCombiner {
if (commandLineArguments.disableAuth) {
config.auth = [{
type: 'none',
options: {}
}]
}
if (!config.auth) {
throw new Error('No authentication type specified')
}
return new CombineAuthentication(config.auth.map((auth) => handleAuthStrategy(auth, config, services)))
}
/**
* Instantiates the authentication handler registered for *config.auth.type*
*
* CLI arguments will be considered.
*/
function handleAuthStrategy (auth: PluginConfig, config: DeepstreamConfig, services: DeepstreamServices): DeepstreamAuthentication {
let AuthenticationHandlerClass
const authStrategies = {
none: OpenAuthentication,
file: FileBasedAuthentication,
http: HttpAuthentication,
storage: StorageBasedAuthentication
}
if (auth.name || auth.path) {
AuthenticationHandlerClass = resolvePluginClass(auth, 'authentication', services.logger)
if (!AuthenticationHandlerClass) {
throw new Error(`unable to resolve authentication handler ${auth.name || auth.path}`)
}
} else if (auth.type && (authStrategies as any)[auth.type]) {
if (auth.options && auth.options.path) {
const req = require
auth.options.users = req(fileUtils.lookupConfRequirePath(auth.options.path))
}
AuthenticationHandlerClass = (authStrategies as any)[auth.type]
} else {
throw new Error(`Unknown authentication type ${auth.type}`)
}
if (config.auth.length > 1) {
if (!auth.options.reportInvalidParameters) auth.options.reportInvalidParameters = false
}
return new AuthenticationHandlerClass(auth.options, services, config)
}
/**
* Instantiates the permission handler registered for *config.permission.type*
*
* CLI arguments will be considered.
*/
function handlePermissionStrategies (config: DeepstreamConfig, services: DeepstreamServices): DeepstreamPermission {
const permission = config.permission
if (!config.permission) {
throw new Error('No permission type specified')
}
if (commandLineArguments.disablePermissions) {
config.permission.type = 'none'
config.permission.options = {}
}
let PermissionHandlerClass
const permissionStrategies = {
config: ConfigPermission,
none: OpenPermission
}
if (permission.name || permission.path) {
PermissionHandlerClass = resolvePluginClass(permission, 'permission', services.logger)
if (!PermissionHandlerClass) {
throw new Error(`unable to resolve plugin ${permission.name || permission.path}`)
}
} else if (permission.type && (permissionStrategies as any)[permission.type]) {
if (config.permission.options && config.permission.options.path) {
const req = require
config.permission.options.permissions = req(fileUtils.lookupConfRequirePath(config.permission.options.path))
}
PermissionHandlerClass = (permissionStrategies as any)[permission.type]
} else {
throw new Error(`Unknown permission type ${permission.type}`)
}
return new PermissionHandlerClass(permission.options, services, config)
}
/**
* Instantiates the monitoring handlers registered for *config.monitoring.type*
*
*/
function handleMonitoringPlugins (config: DeepstreamConfig, services: DeepstreamServices): DeepstreamMonitoring {
if (!config.monitoring) {
config.monitoring = [{
type: 'none',
options: {}
}]
} else {
// this is in order to make it backwards compatible
if (!Array.isArray(config.monitoring)) {
config.monitoring = [config.monitoring]
}
}
return new CombineMonitoring(config.monitoring.map((monitoringConfig: PluginConfig) => handleMonitoring(monitoringConfig, config, services)))
}
function handleMonitoring (monitoringConfig: PluginConfig, config: DeepstreamConfig, services: DeepstreamServices): DeepstreamMonitoring {
let MonitoringClass
const monitoringPlugins = {
default: NoopMonitoring,
none: NoopMonitoring,
http: HTTPMonitoring,
log: LogMonitoring
}
if (monitoringConfig.name || monitoringConfig.path) {
return new (resolvePluginClass(monitoringConfig, 'monitoring', services.logger))(monitoringConfig.options, services, config)
} else if (monitoringConfig.type && (monitoringPlugins as any)[monitoringConfig.type]) {
MonitoringClass = (monitoringPlugins as any)[monitoringConfig.type]
} else {
throw new Error(`Unknown monitoring type ${monitoringConfig.type}`)
}
return new MonitoringClass(monitoringConfig.options, services, config)
}
function handleHTTPServer (config: DeepstreamConfig, services: DeepstreamServices): DeepstreamHTTPService {
let HttpServerClass
const httpPlugins = {
default: NodeHTTP
}
if (commandLineArguments.host) {
config.httpServer.options.host = commandLineArguments.host
}
if (commandLineArguments.port) {
config.httpServer.options.port = commandLineArguments.port
}
if (config.httpServer.name || config.httpServer.path) {
return new (resolvePluginClass(config.httpServer, 'httpServer', services.logger))(config.httpServer.options, services, config)
} else if (config.httpServer.type && (httpPlugins as any)[config.httpServer.type]) {
HttpServerClass = (httpPlugins as any)[config.httpServer.type]
} else if (config.httpServer.type === 'uws') {
try {
const { UWSHTTP } = require('../services/http/uws/uws-http')
HttpServerClass = UWSHTTP
} catch (e) {
throw new Error('Error loading uws http service, this is most likely due to uWebsocket.js not being supported on this platform')
}
} else {
throw new Error(`Unknown httpServer type ${config.httpServer.type}`)
}
return new HttpServerClass(config.httpServer.options, services, config)
}
function handleTelemetry (config: DeepstreamConfig, services: DeepstreamServices): DeepstreamMonitoring {
let TelemetryPlugin
const telemetryPlugins = {
deepstreamIO: DeepstreamIOTelemetry
}
if (config.telemetry.name || config.telemetry.path) {
return new (resolvePluginClass(config.telemetry, 'telemetry', services.logger))(config.telemetry.options, services, config)
} else if (config.telemetry.type && (telemetryPlugins as any)[config.telemetry.type]) {
TelemetryPlugin = (telemetryPlugins as any)[config.telemetry.type]
} else {
throw new Error(`Unknown telemetry type ${config.telemetry.type}`)
}
return new TelemetryPlugin(config.telemetry.options, services, config)
}
================================================
FILE: src/config/config-validator.ts
================================================
import {Ajv} from 'ajv'
import addFormat from 'ajv-formats'
import betterAjvErrors from 'better-ajv-errors'
import { LOG_LEVEL } from '@deepstream/types'
const LogLevelValidation = {
type: ['integer'],
enum: [
LOG_LEVEL.DEBUG,
LOG_LEVEL.INFO,
LOG_LEVEL.WARN,
LOG_LEVEL.ERROR,
LOG_LEVEL.OFF
]
}
function getPluginOptions (name: string, types: string[], properties: any) {
return {
[name]: {
type: 'object',
properties: {
type: { type: 'string', enum: types },
name: { type: 'string', minLength: 1 },
path: { type: 'string', minLength: 1 },
options: {
type: 'object',
properties
}
},
oneRequired: ['type', 'name', 'path']
}
}
}
const generalOptions = {
libDir: { type: ['string', 'null'] },
serverName: { type: 'string', minLength: 1 },
showLogo: { type: 'boolean' },
exitOnFatalError: { type: 'boolean' },
dependencyInitializationTimeout: { type: 'number', minimum: 1000 },
logLevel: LogLevelValidation
}
const enabledFeatures = {
enabledFeatures: {
record: { type: 'boolean' },
event: { type: 'boolean' },
rpc: { type: 'boolean' },
presence: { type: 'boolean' },
monitoring: { type: 'boolean' },
}
}
const rpcOptions = {
rpc: {
type: ['object'],
ackTimeout: { type: 'integer', minimum: 1 },
responseTimeout: { type: 'integer', minimum: 1 }
}
}
const recordOptions = {
record: {
type: ['object'],
cacheRetrievalTimeout: { type: 'integer', minimum: 50 },
storageRetrievalTimeout: { type: 'integer', minimum: 50 },
storageExclusionPrefixes: { type: ['null', 'array'], items: { type: 'string' } },
storageHotPathPrefixes: { type: ['null', 'array'], items: { type: 'string' } }
}
}
const listenOptions = {
listen: {
type: ['object'],
shuffleProviders: { type: 'boolean' },
responseTimeout: { type: 'integer', minimum: 50 },
rematchInterval: { type: 'integer', minimum: 50 },
matchCooldown: { type: 'integer', minimum: 50 },
}
}
const httpServer = getPluginOptions(
'httpServer',
['default', 'uws'],
{
host: { type: 'string', minLength: 1 },
port: { type: 'integer', minimum: 1 },
allowAllOrigins: { type: 'boolean' },
origins: { type: 'array', items: { type: 'string', format: 'uri' } },
}
)
const cacheOptions = getPluginOptions(
'cache',
['default'],
{
}
)
const storageOptions = getPluginOptions(
'storage',
['default'],
{
}
)
const telemetryOptions = getPluginOptions(
'telemetry',
['deepstreamIO'],
{
enabled: { type: 'boolean' }
}
)
const authenticationOptions = {
auth: {
type: 'array',
items: {
properties: {
type: { type: 'string', enum: ['none', 'file', 'http', 'storage'] },
name: { type: 'string', minLength: 1 },
path: { type: 'string', minLength: 1 },
options: {
type: 'object',
properties: {
hash: { type: 'string', minLength: 1 },
iterations: { type: 'integer', minimum: 1 },
keyLength: { type: 'integer', minimum: 1 },
createUser: { type: 'boolean' },
table: { type: 'string', minLength: 1 },
endpointUrl: { type: 'string', format: 'uri'},
permittedStatusCodes: { type: 'array', items: { type: 'integer' } },
requestTimeout: { type: 'integer', minimum: 1 },
}
}
}
}
}
}
const permissionOptions = getPluginOptions(
'permission',
['config', 'none'],
{
path: { type: 'string', minLength: 1 },
maxRuleIterations: { type: 'integer', minimum: 1 },
cacheEvacuationInterval: { type: 'integer', minimum: 1 }
}
)
const connEndpointsOptions = {
connectionEndpoints: {
type: 'array',
items: {
properties: {
type: { type: 'string', enum: ['ws-text', 'ws-json', 'ws-binary', 'http', 'mqtt'] },
name: { type: 'string', minLength: 1 },
path: { type: 'string', minLength: 1 },
options: {
type: 'object',
properties: {
port: { type: 'integer', minimum: 1 },
host: { type: 'string', minLength: 1 },
healthCheckPath: { type: 'string', minLength: 1 },
maxMessageSize: { type: 'integer', minimum: 0 },
// WEBSOCKET
urlPath: { type: 'string', minLength: 1 },
heartbeatInterval: { type: 'integer', minimum: 1 },
outgoingBufferTimeout: { type: 'integer', minimum: 0 },
unauthenticatedClientTimeout: { type: ['integer', 'boolean'], minimum: 1 },
maxAuthAttempts: { type: 'integer', minimum: 1 },
// HTTP
allowAuthData: { type: 'boolean' },
enableAuthEndpoint: { type: 'boolean' },
authPath: { type: 'string', minLength: 1 },
postPath: { type: 'string', minLength: 1 },
getPath: { type: 'string', minLength: 1 },
}
}
}
}
}
}
const loggerOptions = getPluginOptions(
'logger',
['default', 'json'],
{
options: {
colors: { type: 'boolean' },
logLevel: LogLevelValidation
}
}
)
const subscriptionsOptions = getPluginOptions(
'subscriptions',
['default'],
{
subscriptionsSanityTimer: { type: 'integer', minimum: 50 },
}
)
const monitoringOptions = {
monitoring: {
type: ['array', 'object'],
items: {
properties: {
type: { type: 'string', enum: ['none', 'log', 'http'] },
name: { type: 'string', minLength: 1 },
path: { type: 'string', minLength: 1 },
},
options: { type: 'object'}
}
}
}
const locksOptions = getPluginOptions(
'locks',
['default'],
{
holdTimeout: { type: 'integer', minimum: 50 },
requestTimeout: { type: 'integer', minimum: 50 },
}
)
const clusterNodeOptions = getPluginOptions(
'clusterNode',
['default', 'vertical'],
{
}
)
const clusterRegistryOptions = getPluginOptions(
'clusterRegistry',
['default'],
{
keepAliveInterval: { type: 'integer', minimum: 1 },
activeCheckInterval: { type: 'integer', minimum: 1 },
nodeInactiveTimeout: { type: 'integer', minimum: 1 },
}
)
const clusterStatesOptions = getPluginOptions(
'clusterStates',
['default'],
{
reconciliationTimeout: { type: 'integer', minimum: 1 },
}
)
const customPluginsOptions = {
plugins: {
type: ['null', 'object'],
properties: {
}
}
}
const schema = {
additionalProperties: false,
properties: {
...generalOptions,
...enabledFeatures,
...rpcOptions,
...recordOptions,
...listenOptions,
...httpServer,
...connEndpointsOptions,
...loggerOptions,
...cacheOptions,
...storageOptions,
...authenticationOptions,
...permissionOptions,
...subscriptionsOptions,
...monitoringOptions,
...telemetryOptions,
...locksOptions,
...clusterNodeOptions,
...clusterRegistryOptions,
...clusterStatesOptions,
...customPluginsOptions
}
}
export const validate = function (config: Object): void {
const ajv = new Ajv({ allErrors: true, strict: false })
addFormat(ajv)
const validator = ajv.compile(schema)
const valid = validator(config)
if (!valid) {
const output = betterAjvErrors(schema, config, validator.errors ?? [], { format: 'js' })
console.error('There was an error validating your configuration:')
output.forEach((e, i) => console.error(`${i + 1})${e.error}${e.suggestion ? `. ${e.suggestion}` : ''}`))
process.exit(1)
}
}
================================================
FILE: src/config/ds-info.ts
================================================
import * as fs from 'fs'
import * as path from 'path'
import * as os from 'os'
import * as glob from 'glob'
export const getDSInfo = (libDir?: string) => {
let meta
let pkg
try {
meta = require('../../meta.json')
} catch (err) {
// if deepstream is not installed as binary (source or npm)
pkg = require('../../package.json')
meta = {
deepstreamVersion: pkg.version,
ref: pkg.gitHead || pkg._resolved || 'N/A',
buildTime: 'N/A'
}
}
meta.platform = os.platform()
meta.arch = os.arch()
meta.nodeVersion = process.version
if (libDir) {
fetchLibs(libDir, meta)
}
return meta
}
const fetchLibs = (libDir: string, meta: any) => {
const directory = libDir || 'lib'
const files = glob.sync(path.join(directory, '*', 'package.json'))
meta.libs = files.map((filePath: any) => {
const pkg = fs.readFileSync(filePath, 'utf8')
const object = JSON.parse(pkg)
return `${object.name}:${object.version}`
})
}
================================================
FILE: src/config/file-utils.spec.ts
================================================
import 'mocha'
import { expect } from 'chai'
import * as fileUtils from './file-utils'
const path = require('path')
describe('fileUtils tests', () => {
it('check cases with no or a relative prefix', () => {
// node style path (no dot at the start and not absolute path)
expect(fileUtils.lookupRequirePath('foo-bar')).to.deep.equal('foo-bar')
expect(fileUtils.lookupRequirePath('dir/foo-bar')).to.deep.equal('dir/foo-bar')
expect(fileUtils.lookupRequirePath('foo-bar', 'pre')).to.deep.equal(path.resolve('pre', 'foo-bar'))
expect(fileUtils.lookupRequirePath('dir/foo-bar', 'pre')).to.deep.equal(path.resolve('pre', 'dir', 'foo-bar'))
// use an absolute path for the fileUtilsname
expect(fileUtils.lookupRequirePath('/usr/foo-bar')).to.deep.equal('/usr/foo-bar')
expect(fileUtils.lookupRequirePath('/usr/dir/foo-bar')).to.deep.equal('/usr/dir/foo-bar')
expect(fileUtils.lookupRequirePath('/usr/foo-bar', 'pre')).to.deep.equal('/usr/foo-bar')
expect(fileUtils.lookupRequirePath('/usr/dir/foo-bar', 'pre')).to.deep.equal('/usr/dir/foo-bar')
// use a relative path for the fileUtilsname
expect(fileUtils.lookupRequirePath('./foo-bar')).to.deep.equal(path.resolve('foo-bar'))
expect(fileUtils.lookupRequirePath('./dir/foo-bar')).to.deep.equal(path.resolve('dir', 'foo-bar'))
expect(fileUtils.lookupRequirePath('./foo-bar', 'pre')).to.deep.equal(path.resolve('pre', 'foo-bar'))
expect(fileUtils.lookupRequirePath('./dir/foo-bar', 'pre')).to.deep.equal(path.resolve('pre', 'dir', 'foo-bar'))
})
it('check cases with an absolute prefix', () => {
// node style path (no dot at the start and not absolute path)
expect(fileUtils.lookupRequirePath('foo-bar', '/pre')).to.deep.equal(path.resolve('/pre', 'foo-bar'))
expect(fileUtils.lookupRequirePath('dir/foo-bar', '/pre')).to.deep.equal(path.resolve('/pre', 'dir', 'foo-bar'))
// use an absolute path for the fileUtilsname
expect(fileUtils.lookupRequirePath('/usr/foo-bar', '/pre')).to.deep.equal('/usr/foo-bar')
expect(fileUtils.lookupRequirePath('/usr/dir/foo-bar', '/pre')).to.deep.equal('/usr/dir/foo-bar')
// use a relative path for the fileUtilsname
expect(fileUtils.lookupRequirePath('./foo-bar', '/pre')).to.deep.equal(path.resolve('/pre', 'foo-bar'))
expect(fileUtils.lookupRequirePath('./dir/foo-bar', '/pre')).to.deep.equal(path.resolve('/pre', 'dir', 'foo-bar'))
})
})
================================================
FILE: src/config/file-utils.ts
================================================
import * as fs from 'fs'
import * as path from 'path'
/**
* Append the global library directory as the prefix to any path
* used here
*/
export const lookupLibRequirePath = function (filePath: string): string {
// @ts-ignore
return exports.lookupRequirePath(filePath, global.deepstreamLibDir)
}
/**
* Append the global configuration directory as the prefix to any path
* used here
*/
export const lookupConfRequirePath = function (filePath: string): string {
// @ts-ignore
return exports.lookupRequirePath(filePath, global.deepstreamConfDir)
}
/**
* Resolve a path which will be passed to *require*.
*
* If a prefix is not set the filePath will be returned
* Otherwise it will either replace return a new path prepended with the prefix.
* If the prefix is not an absolute path it will also prepend the CWD.
*
* file || relative (starts with .) | absolute | else (npm module path)
* -----------------------------------------------------------------------------
* *prefix || *CWD + prefix + file | file | *CWD + prefix + file
* *no prefix || CWD + file | file | file (resolved by nodes require)
*
* *CWD = ignore CWD if prefix is absolute
*/
export const lookupRequirePath = function (filePath: string, prefix?: string): string {
// filePath is absolute
if (path.parse(filePath).root !== '') {
return filePath
}
// filePath is not relative (and not absolute)
if (filePath[0] !== '.') {
if (prefix == null) {
return filePath
}
return resolvePrefixAndFile(filePath, prefix)
}
// filePath is relative, starts with .
if (prefix == null) {
return path.resolve(process.cwd(), filePath)
}
return resolvePrefixAndFile(filePath, prefix)
}
/**
* Returns true if a file exists for a given path
*/
export const fileExistsSync = function (filePath: string): boolean {
try {
fs.lstatSync(filePath)
return true
} catch (e) {
return false
}
}
/**
* Append the prefix to the current working directory,
* or use it as an absolute path
*/
function resolvePrefixAndFile (nonAbsoluteFilePath: string, prefix: string): string {
// prefix is not absolute
if (path.parse(prefix).root === '') {
return path.resolve(process.cwd(), prefix, nonAbsoluteFilePath)
}
// prefix is absolute
return path.resolve(prefix, nonAbsoluteFilePath)
}
================================================
FILE: src/config/js-yaml-loader.spec.ts
================================================
import 'mocha'
import { expect } from 'chai'
import { spy } from 'sinon'
import * as path from 'path'
const proxyquire = require('proxyquire').noPreserveCache()
const utils = require('../utils/utils')
const jsYamlLoader = require('./js-yaml-loader')
function setUpStub (fileExists?, fileContent?) {
const fileMock: any = {}
if (typeof fileExists !== 'undefined') {
fileMock.fileExistsSync = function () {
return !!fileExists
}
}
const fsMock: any = {}
if (typeof fileContent !== 'undefined') {
fsMock.readFileSync = function () {
return fileContent
}
}
const configLoader = proxyquire('./js-yaml-loader', {
'./file-utils': fileMock,
'fs': fsMock
})
spy(fileMock, 'fileExistsSync')
spy(fsMock, 'readFileSync')
return {
configLoader,
fileMock
}
}
describe.skip('js-yaml-loader', () => {
afterEach(() => {
global.deepstreamConfDir = null
global.deepstreamLibDir = null
global.deepstreamCLI = null
})
describe('js-yaml-loader loads and parses json files', () => {
const jsonLoader = {
load: jsYamlLoader.readAndParseFile
}
it('initialises the loader', () => {
expect(typeof jsonLoader.load).to.equal('function')
})
it('errors if invoked with an invalid path', (done) => {
jsonLoader.load(null, (err, result) => {
expect(err.toString()).to.contain('path')
expect(result).to.equal(undefined)
done()
})
})
it('successfully loads and parses a valid JSON file', (done) => {
jsonLoader.load('./src/test/config/basic-valid-json.json', (err, result) => {
expect(err).to.equal(null)
expect(result).to.deep.equal({ pet: 'pug' })
done()
})
})
it('errors when trying to load non existant file', (done) => {
jsonLoader.load('./src/test/config/does-not-exist.json', (err, result) => {
expect(err.toString()).to.contain('no such file or directory')
expect(result).to.equal(undefined)
done()
})
})
})
describe('js-yaml-loader', () => {
it('loads the default yml file', () => {
const loader = jsYamlLoader
const result = loader.loadConfig()
let defaultYamlConfig = result.config
expect(result.file).to.deep.equal(path.join('conf', 'config.yml'))
// TODO
// expect(defaultYamlConfig.serverName).to.have.type('string')
defaultYamlConfig = utils.merge(defaultYamlConfig, {
permission: { type: 'none', options: null },
authentication: null,
plugins: null,
serverName: null,
logger: null
})
expect(defaultYamlConfig).not.to.equal(null)
})
it('tries to load yaml, js and json file and then default', () => {
const stub = setUpStub(false)
expect(() => {
stub.configLoader.loadConfig()
}).to.throw()
expect(stub.fileMock.fileExistsSync).to.have.callCount(28)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith(path.join('conf', 'config.js'))
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith(path.join('conf', 'config.json'))
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith(path.join('conf', 'config.yml'))
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('/etc/deepstream/config.js')
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('/etc/deepstream/config.json')
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('/etc/deepstream/config.yml')
})
it('load a custom yml file path', () => {
const stub = setUpStub()
const config = stub.configLoader.loadConfig('./src/test/config/config.yml').config
expect(stub.fileMock.fileExistsSync).to.have.callCount(1)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('./src/test/config/config.yml')
expect(config.serverName).not.to.equal(undefined)
expect(config.serverName).not.to.deep.equal('')
expect(config.serverName).not.to.deep.equal('UUID')
expect(config.port).to.deep.equal(1337)
expect(config.host).to.deep.equal('1.2.3.4')
expect(config.colors).to.deep.equal(false)
expect(config.showLogo).to.deep.equal(false)
// TODO
// expect(config.logLevel).to.deep.equal(C.LOG_LEVEL.ERROR)
})
it('loads a missing custom yml file path', () => {
const stub = setUpStub()
expect(() => {
stub.configLoader.loadConfig(null, { config: './src/test/config/does-not-exist.yml' })
}).to.throw('Configuration file not found at: ./src/test/config/does-not-exist.yml')
})
it('load a custom json file path', () => {
const stub = setUpStub(true, JSON.stringify({ port: 1001 }))
const config = stub.configLoader.loadConfig(null, { config: './foo.json' }).config
expect(stub.fileMock.fileExistsSync).to.have.callCount(1)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('./foo.json')
expect(config.port).to.deep.equal(1001)
})
it('load a custom js file path', () => {
const stub = setUpStub()
let config = stub.configLoader.loadConfig(null, { config: './src/test/config/config.js' }).config
expect(stub.fileMock.fileExistsSync).to.have.callCount(1)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('./src/test/config/config.js')
expect(config.port).to.deep.equal(1002)
config = stub.configLoader.loadConfig(null, { config: path.join(process.cwd(), 'src/test/config/config.js') }).config
expect(stub.fileMock.fileExistsSync).to.have.callCount(2)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith(path.join(process.cwd(), 'test/test/config/config.js'))
expect(config.port).to.deep.equal(1002)
})
it('fails if the custom file format is not supported', () => {
const stub = setUpStub(true, 'content doesnt matter here')
expect(() => {
// tslint:disable-next-line:no-unused-expression
stub.configLoader.loadConfig(null, { config: './config.foo' }).config
}).to.throw('.foo is not supported as configuration file')
})
it('fails if the custom file was not found', () => {
const stub = setUpStub(false)
expect(() => {
// tslint:disable-next-line:no-unused-expression
stub.configLoader.loadConfig(null, { config: './not-existing-config' }).config
}).to.throw('Configuration file not found at: ./not-existing-config')
expect(stub.fileMock.fileExistsSync).to.have.callCount(1)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('./not-existing-config')
})
it('fails if the yaml file is invalid', () => {
const stub = setUpStub()
expect(() => {
// tslint:disable-next-line:no-unused-expression
stub.configLoader.loadConfig(null, { config: './src/test/config/config-broken.yml' }).config
}).to.throw(/asdsad: ooops/)
expect(stub.fileMock.fileExistsSync).to.have.callCount(1)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('./src/test/config/config-broken.yml')
})
it('fails if the js file is invalid', () => {
const stub = setUpStub()
expect(() => {
// tslint:disable-next-line:no-unused-expression
stub.configLoader.loadConfig(null, { config: './src/test/config/config-broken.js' }).config
}).to.throw(/foobarBreaksIt is not defined/)
expect(stub.fileMock.fileExistsSync).to.have.callCount(1)
expect(stub.fileMock.fileExistsSync).to.have.been.calledWith('./src/test/config/config-broken.js')
})
})
describe('supports environment variable substitution', () => {
let configLoader
beforeEach(() => {
process.env.ENVIRONMENT_VARIABLE_TEST_1 = 'an_environment_variable_value'
process.env.ENVIRONMENT_VARIABLE_TEST_2 = 'another_environment_variable_value'
process.env.EXAMPLE_HOST = 'host'
process.env.EXAMPLE_PORT = '1234'
configLoader = jsYamlLoader
})
it('does environment variable substitution for yaml', () => {
const config = configLoader.loadConfig(null, { config: './src/test/config/config.yml' }).config
expect(config.environmentvariable).to.equal('an_environment_variable_value')
expect(config.another.environmentvariable).to.equal('another_environment_variable_value')
// expect(config.thisenvironmentdoesntexist).to.equal('DOESNT_EXIST')
expect(config.multipleenvs).to.equal('host:1234')
})
it('does environment variable substitution for json', () => {
const config = configLoader.loadConfig(null, { config: './src/test/config/json-with-env-variables.json' }).config
expect(config.environmentvariable).to.equal('an_environment_variable_value')
expect(config.another.environmentvariable).to.equal('another_environment_variable_value')
// expect(config.thisenvironmentdoesntexist).to.equal('DOESNT_EXIST')
expect(config.multipleenvs).to.equal('host:1234')
})
})
describe('merges in deepstreamCLI options', () => {
let configLoader
beforeEach(() => {
global.deepstreamCLI = {
port: 5555
}
configLoader = jsYamlLoader
})
afterEach(() => {
delete process.env.deepstreamCLI
})
it('does cli substitution', () => {
const config = configLoader.loadConfig().config
expect(config.connectionEndpoints.websocket.options.port).to.deep.equal(5555)
})
})
describe('load plugins by relative path property', () => {
let services
beforeEach(() => {
const fileMock = {
fileExistsSync () {
return true
}
}
const fsMock = {
readFileSync (filePath) {
if (filePath === './config.json') {
return `{
"plugins": {
"logger": {
"path": "./logger"
},
"cache": {
"path": "./cache",
"options": { "foo": 3, "bar": 4 }
}
}
}`
}
throw new Error(`should not require any other file: ${filePath}`)
}
}
const loggerModule = function (options) { return options }
loggerModule['@noCallThru'] = true
loggerModule['@global'] = true
class CacheModule {
public options: any
constructor (options) {
this.options = options
}
}
CacheModule['@noCallThru'] = true
CacheModule['@global'] = true
const configLoader = proxyquire('./js-yaml-loader', {
'fs': fsMock,
'./file-utils': fileMock,
[path.resolve('./logger')]: loggerModule,
[path.resolve('./cache')]: CacheModule
})
services = configLoader.loadConfig(null, { config: './config.json' }).services
})
it('load plugins', () => {
expect(services.cache.options).to.deep.equal({ foo: 3, bar: 4 })
})
})
describe.skip('load plugins by path property (npm module style)', () => {
let services
beforeEach(() => {
const fileMock = {
fileExistsSync () {
return true
}
}
const fsMock = {
readFileSync (filePath) {
if (filePath === './config.json') {
return `{
"plugins": {
"cache": {
"path": "foo-bar-qox",
"options": { "foo": 3, "bar": 4 }
}
}
}`
}
throw new Error(`should not require any other file: ${filePath}`)
}
}
// tslint:disable-next-line:max-classes-per-file
class FooBar {
public options: any
constructor (options) {
this.options = options
}
}
FooBar['@noCallThru'] = true
FooBar['@global'] = true
const configLoader = proxyquire('./js-yaml-loader', {
'fs': fsMock,
'./file-utils': fileMock,
'foo-bar-qox': FooBar
})
services = configLoader.loadConfig(null, { config: './config.json' }).services
})
it('load plugins', () => {
expect(services.cache.options).to.deep.equal({ foo: 3, bar: 4 })
})
})
describe('load plugins by name with a name convention', () => {
let services
beforeEach(() => {
const fileMock = {
fileExistsSync () {
return true
}
}
const fsMock = {
readFileSync (filePath) {
if (filePath === './config.json') {
return `{
"plugins": {
"cache": {
"name": "super-cache",
"options": { "foo": 5, "bar": 6 }
},
"storage": {
"name": "super-storage",
"options": { "foo": 7, "bar": 8 }
}
}
}`
}
throw new Error(`should not require any other file: ${filePath}`)
}
}
// tslint:disable-next-line:max-classes-per-file
class SuperCache {
public options: any
constructor (options) {
this.options = options
}
}
SuperCache['@noCallThru'] = true
SuperCache['@global'] = true
// tslint:disable-next-line:max-classes-per-file
class SuperStorage {
public options: any
constructor (options) {
this.options = options
}
}
SuperStorage['@noCallThru'] = true
SuperStorage['@global'] = true
const configLoader = proxyquire('./js-yaml-loader', {
'fs': fsMock,
'./file-utils': fileMock,
'deepstream.io-cache-super-cache': SuperCache,
'deepstream.io-storage-super-storage': SuperStorage
})
services = configLoader.loadConfig(null, {
config: './config.json'
}).services
})
it('load plugins', () => {
expect(services.cache.options).to.deep.equal({ foo: 5, bar: 6 })
expect(services.storage.options).to.deep.equal({ foo: 7, bar: 8 })
})
})
describe('load plugins by name with a name convention with lib prefix', () => {
let services
beforeEach(() => {
const fileMock = {
fileExistsSync () {
return true
}
}
const fsMock = {
readFileSync (filePath) {
if (filePath === './config.json') {
return `{
"plugins": {
"cache": {
"name": "super-cache",
"options": { "foo": -1, "bar": -2 }
},
"storage": {
"name": "super-storage",
"options": { "foo": -3, "bar": -4 }
}
}
}`
}
throw new Error(`should not require any other file: ${filePath}`)
}
}
// tslint:disable-next-line:max-classes-per-file
class SuperCache {
public options: any
constructor (options) {
this.options = options
}
}
SuperCache['@noCallThru'] = true
SuperCache['@global'] = true
// tslint:disable-next-line:max-classes-per-file
class SuperStorage {
public options: any
constructor (options) {
this.options = options
}
}
SuperStorage['@noCallThru'] = true
SuperStorage['@global'] = true
// tslint:disable-next-line:max-classes-per-file
class HTTPMock {
public options: any
constructor (options) {
this.options = options
}
}
HTTPMock['@noCallThru'] = true
HTTPMock['@global'] = true
const configLoader = proxyquire('./js-yaml-loader', {
'fs': fsMock,
'./file-utils': fileMock,
[path.resolve(process.cwd(), 'foobar', 'deepstream.io-cache-super-cache')]: SuperCache,
[path.resolve(process.cwd(), 'foobar', 'deepstream.io-storage-super-storage')]: SuperStorage,
[path.resolve(process.cwd(), 'foobar', 'deepstream.io-connection-http')]: HTTPMock
})
services = configLoader.loadConfig(null, {
config: './config.json',
libDir: 'foobar'
}).services
})
it('load plugins', () => {
expect(services.cache.options).to.deep.equal({ foo: -1, bar: -2 })
expect(services.storage.options).to.deep.equal({ foo: -3, bar: -4 })
})
})
describe('load plugins by name with a name convention with an absolute lib prefix', () => {
let services
beforeEach(() => {
const fileMock = {
fileExistsSync () {
return true
}
}
const fsMock = {
readFileSync (filePath) {
if (filePath === './config.json') {
return `{
"plugins": {
"cache": {
"name": "super-cache",
"options": { "foo": -1, "bar": -2 }
},
"storage": {
"name": "super-storage",
"options": { "foo": -3, "bar": -4 }
}
}
}`
}
throw new Error(`should not require any other file: ${filePath}`)
}
}
// tslint:disable-next-line:max-classes-per-file
class SuperCache {
public options: any
constructor (options) {
this.options = options
}
}
SuperCache['@noCallThru'] = true
SuperCache['@global'] = true
// tslint:disable-next-line:max-classes-per-file
class SuperStorage {
public options: any
constructor (options) {
this.options = options
}
}
SuperStorage['@noCallThru'] = true
SuperStorage['@global'] = true
// tslint:disable-next-line:max-classes-per-file
class HTTPMock {
public options: any
constructor (options) {
this.options = options
}
}
HTTPMock['@noCallThru'] = true
HTTPMock['@global'] = true
const configLoader = proxyquire('./js-yaml-loader', {
'fs': fsMock,
'./file-utils': fileMock,
[path.resolve('/foobar', 'deepstream.io-cache-super-cache')]: SuperCache,
[path.resolve('/foobar', 'deepstream.io-storage-super-storage')]: SuperStorage,
[path.resolve('/foobar', 'deepstream.io-connection-http')]: HTTPMock
})
services = configLoader.loadConfig(null, {
config: './config.json',
libDir: '/foobar'
}).services
})
it('load plugins', () => {
expect(services.cache.options).to.deep.equal({ foo: -1, bar: -2 })
expect(services.storage.options).to.deep.equal({ foo: -3, bar: -4 })
})
})
})
================================================
FILE: src/config/js-yaml-loader.ts
================================================
import * as fs from 'fs'
import * as yaml from 'js-yaml'
import * as path from 'path'
import { get as getDefaultOptions } from '../default-options'
import { merge } from '../utils/utils'
import { DeepstreamConfig, LOG_LEVEL, EVENT } from '@deepstream/types'
import Deepstream from '../deepstream.io'
import * as configInitializer from './config-initialiser'
import * as fileUtils from './file-utils'
export type InitialLogs = Array<{
level: LOG_LEVEL
message: string
event: any,
meta: any
}>
const SUPPORTED_EXTENSIONS = ['.yml', '.yaml', '.json', '.js']
const DEFAULT_CONFIG_DIRS = [
'/etc/deepstream/conf',
path.join('.', 'conf', 'config'),
path.join('..', 'conf', 'config')
]
DEFAULT_CONFIG_DIRS.push(path.join(process.argv[1], '..', 'conf', 'config'))
DEFAULT_CONFIG_DIRS.push(path.join(process.argv[1], '..', '..', 'conf', 'config'))
/**
* Reads and parse a general configuration file content.
*/
export const readAndParseFile = function (filePath: string, callback: Function): void {
try {
fs.readFile(filePath, 'utf8', (error, fileContent) => {
if (error) {
return callback(error)
}
try {
const config = parseFile(filePath, fileContent)
return callback(null, config)
} catch (parseError) {
return callback(parseError)
}
})
} catch (error) {
callback(error)
}
}
/**
* Loads a config file without having to initialize it. Useful for one
* off operations such as generating a hash via cli
*/
export const loadConfigWithoutInitialization = async function (filePath: string | null = null, initialLogs: InitialLogs = [], args?: object): Promise<{
config: DeepstreamConfig,
configPath: string
}> {
// @ts-ignore
const argv = args || global.deepstreamCLI || {}
const configPath = setGlobalConfigDirectory(argv, filePath)
let configString = fs.readFileSync(configPath, { encoding: 'utf8' })
configString = configString.replace(/(^#)*#.*$/gm, '$1')
configString = configString.replace(/^\s*\n/gm, '')
configString = lookupConfigPaths(configString)
configString = await loadFiles(configString, initialLogs)
const rawConfig = parseFile(configPath, configString)
const config = extendConfig(rawConfig, argv)
setGlobalLibDirectory(argv, config)
return {
config,
configPath,
}
}
/**
* Loads a file as deepstream config. CLI args have highest priority after the
* configuration file. If some properties are not set they will be defaulted
* to default values defined in the defaultOptions.js file.
* Configuraiton file will be transformed to a deepstream object by evaluating
* some properties like the plugins (logger and connectors).
*/
export const loadConfig = async function (deepstream: Deepstream, filePath: string | null, args?: object) {
const logs: InitialLogs = []
const config = await loadConfigWithoutInitialization(filePath, logs, args)
const result = configInitializer.initialize(deepstream, config.config, logs)
return {
config: result.config,
services: result.services,
file: config.configPath,
}
}
/**
* Parse a general configuration file
* These file extension ans formats are allowed:
* .yml, .js, .json
*
* If no fileContent is passed the file is read synchronously
*/
function parseFile<ConfigType = DeepstreamConfig> (filePath: string, fileContent: string): ConfigType {
const extension = path.extname(filePath)
if (extension === '.yml' || extension === '.yaml') {
return yaml.load(replaceEnvironmentVariables(fileContent)) as unknown as ConfigType
} else if (extension === '.js') {
return require(path.resolve(filePath))
} else if (extension === '.json') {
return JSON.parse(replaceEnvironmentVariables(fileContent))
} else {
throw new Error(`${extension} is not supported as configuration file`)
}
}
/**
* Set the globalConfig prefix that will be used as the directory for ssl, permissions and auth
* relative files within the config file
*/
function setGlobalConfigDirectory (argv: any, filePath?: string | null): string {
const customConfigPath =
argv.c ||
argv.config ||
filePath ||
process.env.DEEPSTREAM_CONFIG_DIRECTORY
const configPath = customConfigPath
? verifyCustomConfigPath(customConfigPath)
: getDefaultConfigPath()
// @ts-ignore
global.deepstreamConfDir = path.dirname(configPath)
return configPath
}
/**
* Set the globalLib prefix that will be used as the directory for the logger
* and plugins within the config file
*/
function setGlobalLibDirectory (argv: any, config: DeepstreamConfig): void {
// @ts-ignore
const libDir =
argv.l ||
argv.libDir ||
(config.libDir && fileUtils.lookupConfRequirePath(config.libDir)) ||
process.env.DEEPSTREAM_LIBRARY_DIRECTORY
// @ts-ignore
global.deepstreamLibDir = libDir
}
/**
* Augments the basic configuration with command line parameters
* and normalizes paths within it
*/
function extendConfig (config: any, argv: any): DeepstreamConfig {
const cliArgs = {}
let key
for (key in getDefaultOptions()) {
(cliArgs as any)[key] = argv[key]
}
return merge({ plugins: {} }, getDefaultOptions(), config, cliArgs) as DeepstreamConfig
}
/**
* Checks if a config file is present at a given path
*/
function verifyCustomConfigPath (configPath: string): string {
if (fileUtils.fileExistsSync(configPath)) {
return configPath
}
throw new Error(`Configuration file not found at: ${configPath}`)
}
/**
* Fallback if no config path is specified. Will attempt to load the file from the default directory
*/
function getDefaultConfigPath (): string {
let filePath
let i
let k
for (k = 0; k < DEFAULT_CONFIG_DIRS.length; k++) {
for (i = 0; i < SUPPORTED_EXTENSIONS.length; i++) {
filePath = DEFAULT_CONFIG_DIRS[k] + SUPPORTED_EXTENSIONS[i]
if (fileUtils.fileExistsSync(filePath)) {
return filePath
}
}
}
throw new Error('No config file found')
}
/**
* Handle the introduction of global environment variables within
* the yml file, allowing value substitution.
*
* For example:
* ```
* host: $HOST_NAME
* port: $HOST_PORT
* ```
*/
function replaceEnvironmentVariables (fileContent: string): string {
const environmentVariable = new RegExp(/\${([^}]+)}/g)
return fileContent.replace(environmentVariable, (a, b) => process.env[b] || '')
}
function lookupConfigPaths (fileContent: string): string {
const matches = fileContent.match(/file\((.*)\)/g)
if (matches) {
matches.forEach((match) => {
const [, filename] = match.match(/file\((.*)\)/) as any
fileContent = fileContent.replace(match, fileUtils.lookupConfRequirePath(filename))
})
}
return fileContent
}
async function loadFiles (fileContent: string, initialLogs: InitialLogs): Promise<string> {
const matches = fileContent.match(/fileLoad\((.*)\)/g)
if (matches) {
const promises = matches.map(async (match) => {
const [, filename] = match.match(/fileLoad\((.*)\)/) as any
try {
let content: string = await new Promise((resolve, reject) =>
fs.readFile(fileUtils.lookupConfRequirePath(filename), { encoding: 'utf8' }, (err, data) => {
err ? reject(err) : resolve(data)
})
)
content = replaceEnvironmentVariables(content)
try {
if (['.yml', '.yaml', '.js', '.json'].includes(path.extname(filename))) {
content = parseFile(filename, content)
}
initialLogs.push({
level: LOG_LEVEL.INFO,
message: `Loaded content from ${fileUtils.lookupConfRequirePath(filename)} for ${match}`,
event: EVENT.CONFIG_TRANSFORM,
meta: undefined
})
} catch (e) {
initialLogs.push({
level: LOG_LEVEL.FATAL,
event: EVENT.CONFIG_ERROR,
message: `Error loading config file, invalid format in file ${fileUtils.lookupConfRequirePath(filename)} for ${match}`,
meta: undefined
})
}
fileContent = fileContent.replace(match, JSON.stringify(content))
} catch (e) {
initialLogs.push({
level: LOG_LEVEL.FATAL,
event: EVENT.CONFIG_ERROR,
message: `Error loading config file, missing file ${fileUtils.lookupConfRequirePath(filename)} for ${match}`,
meta: undefined
})
}
})
await Promise.all(promises)
}
return fileContent
}
================================================
FILE: src/connection-endpoint/base/connection-endpoint.spec.ts
================================================
// import * as C from '../../src/constants'
// const proxyquire
gitextract_5br62wbj/
├── .dockerignore
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.md
│ └── workflows/
│ ├── lint-test.yml
│ └── release.yml
├── .gitignore
├── .gitmodules
├── .npmignore
├── CHANGELOG.md
├── Dockerfile
├── Dockerfile.alpine
├── LICENSE
├── README.md
├── SECURITY.md
├── ascii-logo.txt
├── bin/
│ ├── deepstream-cluster.ts
│ ├── deepstream-daemon.ts
│ ├── deepstream-hash.ts
│ ├── deepstream-info.ts
│ ├── deepstream-nginx.ts
│ ├── deepstream-service.ts
│ ├── deepstream-start.ts
│ └── deepstream.ts
├── conf/
│ ├── config.yml
│ ├── permissions.yml
│ └── users.yml
├── package.json
├── scripts/
│ ├── connector/
│ │ ├── package-connector.sh
│ │ └── test-connector.sh
│ ├── details.js
│ ├── executable-test.js
│ ├── license-aggregator.js
│ ├── linux-package.sh
│ ├── linux-test.sh
│ ├── node-test.js
│ ├── package.sh
│ ├── pkg.js
│ ├── release.sh
│ ├── resources/
│ │ ├── PackageInfo
│ │ ├── daemon/
│ │ │ ├── after-install
│ │ │ ├── after-upgrade
│ │ │ ├── before-remove
│ │ │ └── before-upgrade
│ │ ├── missing-licenses.txt
│ │ └── node.rc
│ ├── sanity-test.sh
│ ├── setup.sh
│ ├── trigger-build.sh
│ └── tsc.sh
├── src/
│ ├── config/
│ │ ├── config-initialiser.spec.ts
│ │ ├── config-initialiser.ts
│ │ ├── config-validator.ts
│ │ ├── ds-info.ts
│ │ ├── file-utils.spec.ts
│ │ ├── file-utils.ts
│ │ ├── js-yaml-loader.spec.ts
│ │ └── js-yaml-loader.ts
│ ├── connection-endpoint/
│ │ ├── base/
│ │ │ ├── connection-endpoint.spec.ts
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper.ts
│ │ ├── http/
│ │ │ ├── connection-endpoint.spec.ts
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper.ts
│ │ ├── mqtt/
│ │ │ ├── connection-endpoint.ts
│ │ │ ├── message-parser.ts
│ │ │ └── socket-wrapper-factory.ts
│ │ └── websocket/
│ │ ├── binary/
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper-factory.ts
│ │ ├── json/
│ │ │ ├── connection-endpoint.ts
│ │ │ └── socket-wrapper-factory.ts
│ │ └── text/
│ │ ├── connection-endpoint.ts
│ │ ├── socket-wrapper-factory.ts
│ │ └── text-protocol/
│ │ ├── constants.ts
│ │ ├── message-builder.ts
│ │ ├── message-parser.ts
│ │ └── utils.ts
│ ├── constants.ts
│ ├── deepstream.io.spec.ts
│ ├── deepstream.io.ts
│ ├── default-options.ts
│ ├── handlers/
│ │ ├── event/
│ │ │ ├── event-handler.spec.ts
│ │ │ └── event-handler.ts
│ │ ├── monitoring/
│ │ │ └── monitoring.ts
│ │ ├── presence/
│ │ │ ├── presence-handler.spec.ts
│ │ │ └── presence-handler.ts
│ │ ├── record/
│ │ │ ├── record-deletion.spec.ts
│ │ │ ├── record-deletion.ts
│ │ │ ├── record-handler-permission.spec.ts
│ │ │ ├── record-handler.spec.ts
│ │ │ ├── record-handler.ts
│ │ │ ├── record-request.spec.ts
│ │ │ ├── record-request.ts
│ │ │ ├── record-transition.spec.ts
│ │ │ ├── record-transition.ts
│ │ │ ├── record-write-acknowledgement.spec.ts
│ │ │ └── test-messages.ts
│ │ └── rpc/
│ │ ├── rpc-handler.spec.ts
│ │ ├── rpc-handler.ts
│ │ ├── rpc-proxy.spec.ts
│ │ ├── rpc-proxy.ts
│ │ └── rpc.ts
│ ├── jif/
│ │ ├── jif-handler.spec.ts
│ │ ├── jif-handler.ts
│ │ └── jif-schema.ts
│ ├── listen/
│ │ ├── listener-registry.spec.ts
│ │ ├── listener-registry.ts
│ │ └── listener-test-utils.ts
│ ├── plugins/
│ │ └── heap-snapshot/
│ │ └── heap-snapshot.ts
│ ├── service/
│ │ ├── daemon.ts
│ │ ├── service.ts
│ │ └── template/
│ │ ├── initd.ts
│ │ └── systemd.ts
│ ├── services/
│ │ ├── authentication/
│ │ │ ├── combine/
│ │ │ │ └── combine-authentication.ts
│ │ │ ├── file/
│ │ │ │ ├── file-based-authentication.spec.ts
│ │ │ │ └── file-based-authentication.ts
│ │ │ ├── http/
│ │ │ │ ├── http-authentication.spec.ts
│ │ │ │ └── http-authentication.ts
│ │ │ ├── open/
│ │ │ │ ├── open-authentication.spec.ts
│ │ │ │ └── open-authentication.ts
│ │ │ └── storage/
│ │ │ └── storage-based-authentication.ts
│ │ ├── cache/
│ │ │ ├── local-cache.spec.ts
│ │ │ └── local-cache.ts
│ │ ├── cluster-node/
│ │ │ ├── single-cluster-node.ts
│ │ │ └── vertical-cluster-node.ts
│ │ ├── cluster-registry/
│ │ │ ├── distributed-cluster-registry.ts
│ │ │ └── distributed-state-registry-factory.ts
│ │ ├── cluster-state/
│ │ │ ├── distributed-state-registry-factory.ts
│ │ │ ├── distributed-state-registry.ts
│ │ │ └── single-state-registry.ts
│ │ ├── http/
│ │ │ ├── node/
│ │ │ │ └── node-http.ts
│ │ │ └── uws/
│ │ │ └── uws-http.ts
│ │ ├── lock/
│ │ │ └── distributed-lock-registry.ts
│ │ ├── logger/
│ │ │ ├── pino/
│ │ │ │ └── pino-logger.ts
│ │ │ └── std/
│ │ │ ├── std-out-logger.spec.ts
│ │ │ └── std-out-logger.ts
│ │ ├── monitoring/
│ │ │ ├── combine-monitoring.ts
│ │ │ ├── http/
│ │ │ │ ├── monitoring-http.spec.ts
│ │ │ │ └── monitoring-http.ts
│ │ │ ├── log/
│ │ │ │ ├── monitoring-log.spec.ts
│ │ │ │ └── monitoring-log.ts
│ │ │ ├── monitoring-base.ts
│ │ │ └── noop-monitoring.ts
│ │ ├── permission/
│ │ │ ├── open/
│ │ │ │ ├── open-permission.spec.ts
│ │ │ │ └── open-permission.ts
│ │ │ └── valve/
│ │ │ ├── config-compiler.spec.ts
│ │ │ ├── config-compiler.ts
│ │ │ ├── config-permission-basic.spec.ts
│ │ │ ├── config-permission-create.spec.ts
│ │ │ ├── config-permission-cross-reference.spec.ts
│ │ │ ├── config-permission-load.spec.ts
│ │ │ ├── config-permission-nested-cross-reference.spec.ts
│ │ │ ├── config-permission-other.spec.ts
│ │ │ ├── config-permission-record-patch.spec.ts
│ │ │ ├── config-permission.ts
│ │ │ ├── config-schema.ts
│ │ │ ├── config-validator.spec.ts
│ │ │ ├── config-validator.ts
│ │ │ ├── path-parser.spec.ts
│ │ │ ├── path-parser.ts
│ │ │ ├── rule-application.ts
│ │ │ ├── rule-cache.spec.ts
│ │ │ ├── rule-cache.ts
│ │ │ ├── rule-parser.spec.ts
│ │ │ ├── rule-parser.ts
│ │ │ ├── rules-map.spec.ts
│ │ │ └── rules-map.ts
│ │ ├── storage/
│ │ │ ├── noop-storage.spec.ts
│ │ │ └── noop-storage.ts
│ │ ├── subscription-registry/
│ │ │ ├── default-subscription-registry-factory.ts
│ │ │ ├── default-subscription-registry.spec.ts
│ │ │ └── default-subscription-registry.ts
│ │ └── telemetry/
│ │ └── deepstreamio-telemetry.ts
│ ├── test/
│ │ ├── common.ts
│ │ ├── config/
│ │ │ ├── basic-permission-config.json
│ │ │ ├── basic-valid-json.json
│ │ │ ├── blank-config.json
│ │ │ ├── config-broken.js
│ │ │ ├── config-broken.yml
│ │ │ ├── config.js
│ │ │ ├── config.yml
│ │ │ ├── empty-map-config.json
│ │ │ ├── exists-test/
│ │ │ │ ├── a-file.js
│ │ │ │ ├── a-file.yml
│ │ │ │ └── a-json-file.json
│ │ │ ├── invalid-permission-conf.json
│ │ │ ├── invalid-user-config.json
│ │ │ ├── json-with-env-variables.json
│ │ │ ├── no-private-events-permission-config.json
│ │ │ ├── sslKey.pem
│ │ │ ├── users-unhashed.json
│ │ │ └── users.json
│ │ ├── helper/
│ │ │ ├── start-test-server.ts
│ │ │ ├── test-helper.ts
│ │ │ ├── test-http-server.ts
│ │ │ └── test-mocks.ts
│ │ └── mock/
│ │ ├── authentication-handler-mock.ts
│ │ ├── http-mock.ts
│ │ ├── logger-mock.ts
│ │ ├── message-connector-mock.ts
│ │ ├── permission-handler-mock.ts
│ │ ├── plugin-mock.ts
│ │ ├── socket-mock.ts
│ │ ├── socket-wrapper-factory-mock.ts
│ │ └── storage-mock.ts
│ └── utils/
│ ├── dependency-initialiser.spec.ts
│ ├── dependency-initialiser.ts
│ ├── json-path.spec.ts
│ ├── json-path.ts
│ ├── message-distributor.spec.ts
│ ├── message-distributor.ts
│ ├── message-processor.spec.ts
│ ├── message-processor.ts
│ ├── utils.spec.ts
│ └── utils.ts
├── telemetry-server/
│ ├── package.json
│ ├── telemetry-server.config.js
│ └── telemetry-server.ts
├── test-e2e/
│ ├── config/
│ │ ├── permissions-complex.json
│ │ └── permissions-open.json
│ ├── framework/
│ │ ├── client-handler.ts
│ │ ├── client.ts
│ │ ├── event.ts
│ │ ├── listening.ts
│ │ ├── presence.ts
│ │ ├── record.ts
│ │ ├── rpc.ts
│ │ ├── utils.ts
│ │ └── world.ts
│ ├── framework-v3/
│ │ ├── client-handler.ts
│ │ ├── client.ts
│ │ ├── event.ts
│ │ ├── listening.ts
│ │ ├── presence.ts
│ │ ├── record.ts
│ │ ├── rpc.ts
│ │ ├── utils.ts
│ │ └── world.ts
│ ├── steps/
│ │ ├── client/
│ │ │ ├── client-definition-step.ts
│ │ │ ├── connection-steps.ts
│ │ │ ├── event-steps.ts
│ │ │ ├── listening-steps.ts
│ │ │ ├── presence-steps.ts
│ │ │ ├── record-steps.ts
│ │ │ └── rpc-steps.ts
│ │ ├── http/
│ │ │ └── http-steps.ts
│ │ └── server/
│ │ └── step-definition-server.ts
│ └── tools/
│ ├── e2e-authentication.ts
│ ├── e2e-cluster-node.ts
│ ├── e2e-harness.ts
│ ├── e2e-logger.ts
│ └── e2e-server-config.ts
├── tsconfig.json
├── tslint.json
└── types/
├── global.d.ts
└── uws.d.ts
SYMBOL INDEX (1125 symbols across 128 files)
FILE: bin/deepstream-cluster.ts
function action (line 23) | function action () {
FILE: bin/deepstream-daemon.ts
function action (line 21) | function action () {
FILE: bin/deepstream-hash.ts
function action (line 13) | async function action (this: any, password: string) {
FILE: bin/deepstream-info.ts
function printMeta (line 14) | async function printMeta (this: any) {
FILE: bin/deepstream-nginx.ts
function execute (line 23) | async function execute (this: any, action: string) {
FILE: bin/deepstream-service.ts
function response (line 19) | function response (error: Error | string | null, result: string) {
function execute (line 27) | function execute (this: any, action: string) {
FILE: bin/deepstream-start.ts
function action (line 22) | function action () {
function parseLogLevel (line 57) | function parseLogLevel (logLevel: string) {
function parseInteger (line 69) | function parseInteger (name: string, port: string) {
function parseBoolean (line 82) | function parseBoolean (name: string, enabled: string) {
FILE: scripts/details.js
function writeMetaFile (line 22) | function writeMetaFile() {
FILE: scripts/license-aggregator.js
constant PRE_HEADER (line 7) | const PRE_HEADER = fs.readFileSync('LICENSE', 'utf8')
constant HEADER (line 8) | const HEADER = `
function traverseDependencies (line 28) | function traverseDependencies(module) {
function doLevel (line 70) | function doLevel(nodePath) {
function licenseText (line 147) | function licenseText (nodePath, cb) {
function isModuleDirectory (line 198) | function isModuleDirectory (dirPath, cb) {
function logError (line 215) | function logError(err, cb) {
FILE: scripts/pkg.js
constant LTS (line 3) | const LTS = process.env.LTS
FILE: src/config/config-initialiser.ts
function handleUUIDProperty (line 149) | function handleUUIDProperty (config: DeepstreamConfig): void {
function handleClusterNode (line 155) | function handleClusterNode (config: DeepstreamConfig, services: any): D...
function handleLogger (line 178) | function handleLogger (config: DeepstreamConfig, services: DeepstreamSer...
function handleCustomPlugins (line 227) | function handleCustomPlugins (config: DeepstreamConfig, services: any): ...
function handleConnectionEndpoints (line 257) | function handleConnectionEndpoints (config: DeepstreamConfig, services: ...
function resolvePluginClass (line 299) | function resolvePluginClass (plugin: PluginConfig, type: string, logger:...
function handleAuthStrategies (line 361) | function handleAuthStrategies (config: DeepstreamConfig, services: Deeps...
function handleAuthStrategy (line 381) | function handleAuthStrategy (auth: PluginConfig, config: DeepstreamConfi...
function handlePermissionStrategies (line 418) | function handlePermissionStrategies (config: DeepstreamConfig, services:...
function handleMonitoringPlugins (line 459) | function handleMonitoringPlugins (config: DeepstreamConfig, services: De...
function handleMonitoring (line 475) | function handleMonitoring (monitoringConfig: PluginConfig, config: Deeps...
function handleHTTPServer (line 496) | function handleHTTPServer (config: DeepstreamConfig, services: Deepstrea...
function handleTelemetry (line 529) | function handleTelemetry (config: DeepstreamConfig, services: Deepstream...
FILE: src/config/config-validator.ts
function getPluginOptions (line 18) | function getPluginOptions (name: string, types: string[], properties: an...
FILE: src/config/file-utils.ts
function resolvePrefixAndFile (line 73) | function resolvePrefixAndFile (nonAbsoluteFilePath: string, prefix: stri...
FILE: src/config/js-yaml-loader.spec.ts
function setUpStub (line 10) | function setUpStub (fileExists?, fileContent?) {
method fileExistsSync (line 252) | fileExistsSync () {
method readFileSync (line 257) | readFileSync (filePath) {
class CacheModule (line 278) | class CacheModule {
method constructor (line 280) | constructor (options) {
method fileExistsSync (line 304) | fileExistsSync () {
method readFileSync (line 309) | readFileSync (filePath) {
class FooBar (line 324) | class FooBar {
method constructor (line 326) | constructor (options) {
method fileExistsSync (line 349) | fileExistsSync () {
method readFileSync (line 354) | readFileSync (filePath) {
class SuperCache (line 374) | class SuperCache {
method constructor (line 376) | constructor (options) {
method constructor (line 439) | constructor (options) {
method constructor (line 513) | constructor (options) {
class SuperStorage (line 383) | class SuperStorage {
method constructor (line 385) | constructor (options) {
method constructor (line 448) | constructor (options) {
method constructor (line 522) | constructor (options) {
method fileExistsSync (line 412) | fileExistsSync () {
method readFileSync (line 417) | readFileSync (filePath) {
class SuperCache (line 437) | class SuperCache {
method constructor (line 376) | constructor (options) {
method constructor (line 439) | constructor (options) {
method constructor (line 513) | constructor (options) {
class SuperStorage (line 446) | class SuperStorage {
method constructor (line 385) | constructor (options) {
method constructor (line 448) | constructor (options) {
method constructor (line 522) | constructor (options) {
class HTTPMock (line 455) | class HTTPMock {
method constructor (line 457) | constructor (options) {
method constructor (line 531) | constructor (options) {
method fileExistsSync (line 486) | fileExistsSync () {
method readFileSync (line 491) | readFileSync (filePath) {
class SuperCache (line 511) | class SuperCache {
method constructor (line 376) | constructor (options) {
method constructor (line 439) | constructor (options) {
method constructor (line 513) | constructor (options) {
class SuperStorage (line 520) | class SuperStorage {
method constructor (line 385) | constructor (options) {
method constructor (line 448) | constructor (options) {
method constructor (line 522) | constructor (options) {
class HTTPMock (line 529) | class HTTPMock {
method constructor (line 457) | constructor (options) {
method constructor (line 531) | constructor (options) {
FILE: src/config/js-yaml-loader.ts
type InitialLogs (line 12) | type InitialLogs = Array<{
constant SUPPORTED_EXTENSIONS (line 19) | const SUPPORTED_EXTENSIONS = ['.yml', '.yaml', '.json', '.js']
constant DEFAULT_CONFIG_DIRS (line 20) | const DEFAULT_CONFIG_DIRS = [
function parseFile (line 103) | function parseFile<ConfigType = DeepstreamConfig> (filePath: string, fil...
function setGlobalConfigDirectory (line 121) | function setGlobalConfigDirectory (argv: any, filePath?: string | null):...
function setGlobalLibDirectory (line 140) | function setGlobalLibDirectory (argv: any, config: DeepstreamConfig): vo...
function extendConfig (line 155) | function extendConfig (config: any, argv: any): DeepstreamConfig {
function verifyCustomConfigPath (line 169) | function verifyCustomConfigPath (configPath: string): string {
function getDefaultConfigPath (line 180) | function getDefaultConfigPath (): string {
function replaceEnvironmentVariables (line 207) | function replaceEnvironmentVariables (fileContent: string): string {
function lookupConfigPaths (line 212) | function lookupConfigPaths (fileContent: string): string {
function loadFiles (line 223) | async function loadFiles (fileContent: string, initialLogs: InitialLogs)...
FILE: src/connection-endpoint/base/connection-endpoint.ts
constant OPEN (line 5) | const OPEN = 'OPEN'
type WebSocketServerConfig (line 7) | interface WebSocketServerConfig {
class BaseWebsocketConnectionEndpoint (line 21) | class BaseWebsocketConnectionEndpoint extends DeepstreamPlugin implement...
method constructor (line 34) | constructor (private options: WebSocketServerConfig, protected service...
method whenReady (line 39) | public async whenReady (): Promise<void> {
method createWebsocketServer (line 43) | public createWebsocketServer () {
method closeWebsocketServer (line 46) | public closeWebsocketServer () {
method onSocketWrapperClosed (line 49) | public onSocketWrapperClosed (socketWrapper: UnauthenticatedSocketWrap...
method setConnectionListener (line 53) | public setConnectionListener (connectionListener: ConnectionListener) {
method getClientVersions (line 57) | public getClientVersions () {
method onMessages (line 68) | public onMessages (socketWrapper: SocketWrapper, messages: Message[]) {
method init (line 74) | public init (): void {
method scheduleFlush (line 92) | public scheduleFlush (socketWrapper: SocketWrapper) {
method flushSockets (line 102) | private flushSockets () {
method getOption (line 110) | protected getOption (option: string) {
method handleParseErrors (line 114) | public handleParseErrors (socketWrapper: SocketWrapper, parseResults: ...
method onConnection (line 146) | public onConnection (socketWrapper: UnauthenticatedSocketWrapper) {
method processConnectionMessage (line 173) | public processConnectionMessage (socketWrapper: UnauthenticatedSocketW...
method authenticateConnection (line 214) | private authenticateConnection (socketWrapper: UnauthenticatedSocketWr...
method sendInvalidAuthMsg (line 278) | private sendInvalidAuthMsg (socketWrapper: UnauthenticatedSocketWrappe...
method registerAuthenticatedSocket (line 293) | private registerAuthenticatedSocket (unauthenticatedSocketWrapper: Una...
method appendDataToSocketWrapper (line 316) | private appendDataToSocketWrapper (socketWrapper: UnauthenticatedSocke...
method processInvalidAuth (line 330) | private processInvalidAuth (clientData: JSONObject, authData: JSONObje...
method processConnectionTimeout (line 359) | private processConnectionTimeout (socketWrapper: UnauthenticatedSocket...
method processAuthResult (line 372) | private processAuthResult (authData: any, socketWrapper: Unauthenticat...
method onSocketClose (line 391) | public onSocketClose (socketWrapper: UnauthenticatedSocketWrapper): vo...
method close (line 408) | public async close () {
FILE: src/connection-endpoint/base/socket-wrapper.ts
method constructor (line 23) | constructor (
method isOpen (line 33) | get isOpen () {
method invalidTypeReceived (line 37) | protected invalidTypeReceived () {
method flush (line 47) | public flush () {
method sendMessage (line 58) | public sendMessage (message: { topic: TOPIC, action: CONNECTION_ACTION }...
method sendAckMessage (line 66) | public sendAckMessage (message: Message, allowBuffering: boolean = true)...
method onMessage (line 76) | public onMessage (messages: Message[]): void {
method destroy (line 83) | public destroy (): void {
method close (line 91) | public close (): void {
method getHandshakeData (line 104) | public getHandshakeData (): any {
method onClose (line 108) | public onClose (callback: (socketWrapper: StatefulSocketWrapper) => void...
method removeOnClose (line 112) | public removeOnClose (callback: (socketWrapper: StatefulSocketWrapper) =...
method sendBuiltMessage (line 116) | public sendBuiltMessage (message: SerializedType, buffer?: boolean): void {
method writeMessage (line 135) | protected writeMessage (socket: any, message: SerializedType) {
FILE: src/connection-endpoint/http/connection-endpoint.spec.ts
method distribute (line 24) | distribute () {}
FILE: src/connection-endpoint/http/connection-endpoint.ts
type HTTPEvents (line 6) | interface HTTPEvents {
type HTTPConnectionEndpointOptionsInterface (line 12) | interface HTTPConnectionEndpointOptionsInterface {
function checkConfigOption (line 22) | function checkConfigOption (config: any, option: string, expectedType?: ...
class HTTPConnectionEndpoint (line 27) | class HTTPConnectionEndpoint extends DeepstreamPlugin implements Deepstr...
method constructor (line 37) | constructor (private pluginOptions: HTTPConnectionEndpointOptionsInter...
method whenReady (line 52) | public async whenReady (): Promise<void> {
method close (line 56) | public async close () {
method getClientVersions (line 59) | public getClientVersions () {
method init (line 66) | public init (): void {
method onMessages (line 92) | public onMessages (socketWrapper: SimpleSocketWrapper, messages: Messa...
method onGetMessage (line 95) | private onGetMessage (meta: DeepstreamHTTPMeta, responseCallback: any) {
method onAuthMessage (line 107) | private onAuthMessage (authData: JSONObject, metadata: DeepstreamHTTPM...
method onPostMessage (line 143) | private onPostMessage (
method createSocketWrapper (line 208) | private createSocketWrapper (
method onMessageAuthResponse (line 231) | private onMessageAuthResponse (
method onSocketMessage (line 310) | private onSocketMessage (
method onSocketError (line 332) | private onSocketError (
method checkComplete (line 351) | private static checkComplete (messageResults: JifResult[], responseCal...
method onRequestTimeout (line 369) | private onRequestTimeout (responseCallback: Function, messageResults: ...
method calculateMessageResult (line 400) | private static calculateMessageResult (messageResults: JifResult[]): s...
method permissionEventEmit (line 424) | private permissionEventEmit (
method onPermissionResponse (line 441) | private onPermissionResponse (
FILE: src/connection-endpoint/http/socket-wrapper.ts
class HTTPSocketWrapper (line 6) | class HTTPSocketWrapper extends EventEmitter implements UnauthenticatedS...
method constructor (line 25) | constructor (private services: DeepstreamServices, private onMessageCa...
method init (line 29) | public init (
method close (line 46) | public close () {
method flush (line 50) | public flush () {
method onMessage (line 53) | public onMessage () {
method getMessage (line 56) | public getMessage () {
method getHandshakeData (line 64) | public getHandshakeData () {
method sendError (line 72) | public sendError (message: Message, event: EVENT, errorMessage: string) {
method sendMessage (line 90) | public sendMessage (message: Message) {
method sendAckMessage (line 108) | public sendAckMessage (message: Message) {
method parseData (line 113) | public parseData (message: Message) {
method parseMessage (line 117) | public parseMessage (serializedMessage: any): ParseResult[] {
method destroy (line 128) | public destroy () {
method onClose (line 131) | public onClose () {
method removeOnClose (line 134) | public removeOnClose () {
FILE: src/connection-endpoint/mqtt/connection-endpoint.ts
type MQTTConnectionEndpointConfig (line 13) | interface MQTTConnectionEndpointConfig extends WebSocketServerConfig {
type MQTTPacket (line 23) | type MQTTPacket = any
type MQTTConnection (line 24) | type MQTTConnection = any
class MQTTConnectionEndpoint (line 31) | class MQTTConnectionEndpoint extends ConnectionEndpoint {
method constructor (line 39) | constructor (private mqttOptions: MQTTConnectionEndpointConfig, servic...
method whenReady (line 45) | public async whenReady (): Promise<void> {
method close (line 51) | public async close (): Promise<void> {
method createWebsocketServer (line 58) | public createWebsocketServer () {
method closeWebsocketServer (line 150) | public async closeWebsocketServer () {
method onSocketWrapperClosed (line 160) | public onSocketWrapperClosed (socketWrapper: SocketWrapper) {
FILE: src/connection-endpoint/mqtt/socket-wrapper-factory.ts
class MQTTSocketWrapper (line 11) | class MQTTSocketWrapper implements UnauthenticatedSocketWrapper {
method constructor (line 25) | constructor (
method isOpen (line 33) | get isOpen () {
method flush (line 37) | public flush () {
method sendMessage (line 43) | public sendMessage (message: { topic: TOPIC, action: CONNECTION_ACTION...
method sendAckMessage (line 51) | public sendAckMessage (message: Message, allowBuffering: boolean = tru...
method getMessage (line 68) | public getMessage (message: Message): Message {
method parseData (line 72) | public parseData (message: Message): true | Error {
method onMessage (line 76) | public onMessage (messages: Message[]): void {
method destroy (line 83) | public destroy (): void {
method close (line 87) | public close (): void {
method parseMessage (line 95) | public parseMessage (serializedMessage: any): ParseResult[] {
method getHandshakeData (line 104) | public getHandshakeData (): any {
method onClose (line 108) | public onClose (callback: (socketWrapper: StatefulSocketWrapper) => vo...
method removeOnClose (line 112) | public removeOnClose (callback: (socketWrapper: StatefulSocketWrapper)...
method sendBuiltMessage (line 116) | public sendBuiltMessage (message: Message, buffer?: boolean): void {
FILE: src/connection-endpoint/websocket/binary/connection-endpoint.ts
class WSBinaryConnectionEndpoint (line 5) | class WSBinaryConnectionEndpoint extends BaseWebsocketConnectionEndpoint...
method constructor (line 7) | constructor (public wsOptions: WebSocketServerConfig, services: Deepst...
method init (line 11) | public async init () {
FILE: src/connection-endpoint/websocket/binary/socket-wrapper-factory.ts
class WSBinarySocketWrapper (line 8) | class WSBinarySocketWrapper extends WSSocketWrapper<Uint8Array> {
method getAckMessage (line 11) | public getAckMessage (message: Message): Uint8Array {
method getMessage (line 15) | public getMessage (message: Message): Uint8Array {
method parseMessage (line 19) | public parseMessage (message: ArrayBuffer): ParseResult[] {
method parseData (line 33) | public parseData (message: Message): true | Error {
FILE: src/connection-endpoint/websocket/json/connection-endpoint.ts
class WSJSONConnectionEndpoint (line 5) | class WSJSONConnectionEndpoint extends WebsocketConnectionEndpoint {
method constructor (line 7) | constructor (public wsOptions: WebSocketServerConfig, services: Deepst...
method init (line 11) | public init () {
FILE: src/connection-endpoint/websocket/json/socket-wrapper-factory.ts
class JSONSocketWrapper (line 6) | class JSONSocketWrapper extends WSSocketWrapper<string> {
method getMessage (line 9) | public getMessage (message: Message): string {
method getAckMessage (line 13) | public getAckMessage (message: Message): string {
method parseMessage (line 17) | public parseMessage (message: string): ParseResult[] {
method parseData (line 31) | public parseData (message: Message): true | Error {
FILE: src/connection-endpoint/websocket/text/connection-endpoint.ts
class WSTextConnectionEndpoint (line 8) | class WSTextConnectionEndpoint extends BaseWebsocketConnectionEndpoint i...
method constructor (line 12) | constructor (public wsOptions: WebSocketServerConfig, services: Deepst...
method init (line 21) | public async init () {
method onConnection (line 26) | public onConnection (socketWrapper: UnauthenticatedSocketWrapper) {
method sendPing (line 36) | private sendPing (socketWrapper: UnauthenticatedSocketWrapper) {
FILE: src/connection-endpoint/websocket/text/socket-wrapper-factory.ts
class TextWSSocketWrapper (line 8) | class TextWSSocketWrapper extends WSSocketWrapper<string> {
method getMessage (line 11) | public getMessage (message: Message): string {
method getAckMessage (line 15) | public getAckMessage (message: Message): string {
method parseMessage (line 19) | public parseMessage (message: string): ParseResult[] {
method parseData (line 28) | public parseData (message: Message): true | Error {
FILE: src/connection-endpoint/websocket/text/text-protocol/constants.ts
constant MESSAGE_SEPERATOR (line 12) | const MESSAGE_SEPERATOR = String.fromCharCode(30) // ASCII Record Sepera...
constant MESSAGE_PART_SEPERATOR (line 13) | const MESSAGE_PART_SEPERATOR = String.fromCharCode(31) // ASCII Unit Sep...
constant PAYLOAD_ENCODING (line 15) | const PAYLOAD_ENCODING = {
constant TOPIC (line 20) | const TOPIC = {
constant PARSER_ACTIONS (line 31) | const PARSER_ACTIONS = {
constant CONNECTION_ACTIONS (line 41) | const CONNECTION_ACTIONS = {
constant AUTH_ACTIONS (line 57) | const AUTH_ACTIONS = {
constant EVENT_ACTIONS (line 70) | const EVENT_ACTIONS = {
constant RECORD_ACTIONS (line 89) | const RECORD_ACTIONS = {
constant RPC_ACTIONS (line 151) | const RPC_ACTIONS = {
constant PRESENCE_ACTIONS (line 175) | const PRESENCE_ACTIONS = {
constant DEEPSTREAM_TYPES (line 200) | const DEEPSTREAM_TYPES = {
constant TOPIC_BYTE_TO_TEXT (line 210) | const TOPIC_BYTE_TO_TEXT = convertMap(TOPIC, 'BYTE', 'TEXT')
constant TOPIC_TEXT_TO_BYTE (line 211) | const TOPIC_TEXT_TO_BYTE = convertMap(TOPIC, 'TEXT', 'BYTE')
constant TOPIC_TEXT_TO_KEY (line 212) | const TOPIC_TEXT_TO_KEY = reverseMap(specifyMap(TOPIC, 'TEXT'))
constant TOPIC_BYTE_TO_KEY (line 213) | const TOPIC_BYTE_TO_KEY = reverseMap(specifyMap(TOPIC, 'BYTE'))
constant TOPIC_BYTES (line 214) | const TOPIC_BYTES = specifyMap(TOPIC, 'BYTE')
constant ACTIONS_BYTE_TO_PAYLOAD (line 216) | const ACTIONS_BYTE_TO_PAYLOAD: any = {}
constant ACTIONS_BYTE_TO_TEXT (line 217) | const ACTIONS_BYTE_TO_TEXT: any = {}
constant ACTIONS_TEXT_TO_BYTE (line 218) | const ACTIONS_TEXT_TO_BYTE: any = {}
constant ACTIONS_BYTES (line 219) | const ACTIONS_BYTES: any = {}
constant ACTIONS_TEXT_TO_KEY (line 220) | const ACTIONS_TEXT_TO_KEY: any = {}
constant ACTIONS_BYTE_TO_KEY (line 221) | const ACTIONS_BYTE_TO_KEY: any = {}
constant ACTIONS (line 223) | const ACTIONS = {
function convertMap (line 247) | function convertMap (map: any, from: any, to: any) {
function specifyMap (line 262) | function specifyMap (map: any, innerKey: any) {
function reverseMap (line 276) | function reverseMap (map: any) {
FILE: src/connection-endpoint/websocket/text/text-protocol/message-builder.ts
constant NWA (line 20) | const NWA = y + '{}'
constant BUILDERS (line 47) | const BUILDERS = {
FILE: src/connection-endpoint/websocket/text/text-protocol/message-parser.ts
function parseJSON (line 32) | function parseJSON (text: string, reviver?: any): any {
FILE: src/connection-endpoint/websocket/text/text-protocol/utils.ts
constant WRITE_ACK_TO_ACTION (line 3) | const WRITE_ACK_TO_ACTION = {}
FILE: src/constants.ts
type STATES (line 4) | enum STATES {
FILE: src/deepstream.io.ts
class Deepstream (line 32) | class Deepstream extends EventEmitter {
method constructor (line 62) | constructor (config: PartialDeepstreamConfig | string | null = null) {
method set (line 100) | public set (key: string, value: any): any {
method isRunning (line 132) | public isRunning (): boolean {
method start (line 144) | public start (): void {
method stop (line 155) | public stop (): void {
method getServices (line 168) | public getServices (): Readonly<DeepstreamServices> {
method getConfig (line 172) | public getConfig (): Readonly<DeepstreamConfig> {
method transition (line 183) | private transition (transitionName: string): void {
method onTransition (line 203) | private onTransition (transition: { from: STATES, to: STATES, name: st...
method configLoaded (line 213) | private configLoaded (): void {
method loggerInit (line 223) | private async loggerInit (): Promise<void> {
method serviceInit (line 249) | private async serviceInit () {
method handlerInit (line 273) | private async handlerInit () {
method pluginsInit (line 325) | private async pluginsInit () {
method connectionEndpointInit (line 345) | private async connectionEndpointInit (): Promise<void> {
method run (line 375) | private run (): void {
method pluginsShutdown (line 383) | private async pluginsShutdown () {
method connectionEndpointShutdown (line 399) | private async connectionEndpointShutdown (): Promise<void> {
method handlerShutdown (line 405) | private async handlerShutdown () {
method serviceShutdown (line 427) | private async serviceShutdown (): Promise<void> {
method loggerShutdown (line 442) | private async loggerShutdown () {
method stopped (line 452) | private stopped (): void {
method loadConfig (line 462) | private async loadConfig (config: PartialDeepstreamConfig | string | n...
method onClientConnected (line 477) | private onClientConnected (socketWrapper: SocketWrapper): void {
method onClientDisconnected (line 481) | private onClientDisconnected (socketWrapper: SocketWrapper): void {
function isConnectionListener (line 486) | function isConnectionListener (object: any): object is ConnectionListener {
FILE: src/default-options.ts
function get (line 20) | function get (): DeepstreamConfig {
FILE: src/handlers/event/event-handler.ts
class EventHandler (line 5) | class EventHandler implements Handler<EventMessage> {
method constructor (line 13) | constructor (config: DeepstreamConfig, private services: DeepstreamSer...
method close (line 21) | public async close () {
method handle (line 29) | public handle (socketWrapper: SocketWrapper | null, message: EventMess...
method triggerEvent (line 66) | public triggerEvent (socket: SocketWrapper | null, message: EventMessa...
FILE: src/handlers/monitoring/monitoring.ts
class MonitoringHandler (line 4) | class MonitoringHandler extends Handler<MonitoringMessage> {
method constructor (line 10) | constructor (config: DeepstreamConfig, services: DeepstreamServices, s...
method handle (line 20) | public handle (socket: SocketWrapper, message: MonitoringMessage) {
FILE: src/handlers/presence/presence-handler.spec.ts
constant EVERYONE (line 5) | const EVERYONE = '%_EVERYONE_%'
FILE: src/handlers/presence/presence-handler.ts
constant EVERYONE (line 5) | const EVERYONE = '%_EVERYONE_%'
class PresenceHandler (line 12) | class PresenceHandler extends Handler<PresenceMessage> implements Connec...
method constructor (line 17) | constructor (config: DeepstreamConfig, private services: DeepstreamSer...
method handle (line 35) | public handle (socketWrapper: SocketWrapper, message: PresenceMessage)...
method onClientConnected (line 97) | public onClientConnected (socketWrapper: SocketWrapper): void {
method onClientDisconnected (line 113) | public onClientDisconnected (socketWrapper: SocketWrapper): void {
method handleQueryAll (line 128) | private handleQueryAll (correlationId: string, socketWrapper: SocketWr...
method handleQuery (line 145) | private handleQuery (users: string[], correlationId: string, socketWra...
method onClientAdded (line 163) | private onClientAdded (username: string): void {
method onClientRemoved (line 184) | private onClientRemoved (username: string): void {
FILE: src/handlers/record/record-deletion.ts
class RecordDeletion (line 5) | class RecordDeletion {
method constructor (line 22) | constructor (config: DeepstreamConfig, services: DeepstreamServices, s...
method onCacheDelete (line 65) | private onCacheDelete (error: string | null): void {
method onStorageDelete (line 70) | private onStorageDelete (error: string | null) {
method stageComplete (line 75) | private stageComplete (error: string | null) {
method done (line 96) | private done (): void {
method destroy (line 107) | private destroy (): void {
method handleError (line 119) | private handleError (errorMsg: string) {
FILE: src/handlers/record/record-handler.ts
class RecordHandler (line 9) | class RecordHandler extends Handler<RecordMessage> {
method constructor (line 19) | constructor (private readonly config: DeepstreamConfig, private readon...
method close (line 34) | public async close () {
method handle (line 45) | public handle (socketWrapper: SocketWrapper | null, message: RecordMes...
method handleClusterUpdate (line 152) | private handleClusterUpdate (message: RecordMessage) {
method recordUpdatedWithoutDeepstream (line 174) | private async recordUpdatedWithoutDeepstream (message: RecordMessage, ...
method head (line 257) | private head (socketWrapper: SocketWrapper, message: RecordMessage, na...
method subscribeAndHeadBulk (line 261) | private subscribeAndHeadBulk (socketWrapper: SocketWrapper, message: R...
method onSubscribeCreateAndRead (line 288) | private onSubscribeCreateAndRead (recordName: string, version: number,...
method onSubscribeAndRead (line 302) | private onSubscribeAndRead (recordName: string, version: number, data:...
method createAndUpdate (line 329) | private createAndUpdate (socketWrapper: SocketWrapper, message: Record...
method forceWrite (line 385) | private forceWrite (recordName: string, message: RecordWriteMessage, s...
method handleForceWriteAcknowledgement (line 419) | public handleForceWriteAcknowledgement (
method create (line 435) | private create (socketWrapper: SocketWrapper, message: RecordMessage, ...
method readAndSubscribe (line 468) | private readAndSubscribe (message: RecordMessage, version: number, dat...
method update (line 501) | private update (socketWrapper: SocketWrapper | null, message: RecordWr...
method broadcastUpdate (line 535) | public broadcastUpdate (name: string, message: RecordMessage, noDelay:...
method transitionComplete (line 543) | public transitionComplete (recordName: string): void {
method removeRecordRequest (line 554) | public removeRecordRequest (recordName: string): void {
method runWhenRecordStable (line 576) | public runWhenRecordStable (recordName: string, callback: Function): v...
method delete (line 590) | private delete (socketWrapper: SocketWrapper, message: RecordMessage) {
method remoteDelete (line 610) | private remoteDelete (message: RecordMessage) {
method onDeleted (line 625) | private onDeleted (name: string, message: RecordMessage, originalSende...
method permissionAction (line 637) | private permissionAction (actionToPermission: RA, message: Message, or...
method onPermissionResponse (line 651) | private onPermissionResponse (
function onRequestError (line 682) | function onRequestError (event: RA, errorMessage: string, recordName: st...
function onSnapshotComplete (line 696) | function onSnapshotComplete (recordName: string, version: number, data: ...
function onHeadComplete (line 710) | function onHeadComplete (name: string, version: number, data: never, soc...
function sendRecord (line 722) | function sendRecord (recordName: string, version: number, data: any, soc...
FILE: src/handlers/record/record-request.ts
type onCompleteCallback (line 5) | type onCompleteCallback = (recordName: string, version: number, data: an...
type onErrorCallback (line 6) | type onErrorCallback = (event: any, errorMessage: string, recordName: st...
function sendError (line 12) | function sendError (
function onStorageResponse (line 28) | function onStorageResponse (
function onCacheResponse (line 58) | function onCacheResponse (
function recordRequest (line 114) | function recordRequest (
function recordRequestBinding (line 151) | function recordRequestBinding (config: DeepstreamConfig, services: Deeps...
FILE: src/handlers/record/record-transition.ts
type Step (line 8) | interface Step {
class RecordTransition (line 13) | class RecordTransition {
method constructor (line 57) | constructor (private name: string, private config: DeepstreamConfig, p...
method hasVersion (line 68) | public hasVersion (version: number): boolean {
method sendVersionExists (line 80) | public sendVersionExists (step: Step): void {
method add (line 114) | public add (socketWrapper: SocketWrapper, message: RecordWriteMessage,...
method destroy (line 181) | public destroy (error?: string | null): void {
method onRecord (line 207) | private onRecord (version: number, data: any, upsert: boolean) {
method next (line 231) | private next (): void {
method setUpWriteAcknowledgement (line 305) | private setUpWriteAcknowledgement (message: Message, socketWrapper: So...
method flushVersionExists (line 319) | private flushVersionExists (): void {
method handleWriteAcknowledgement (line 326) | private handleWriteAcknowledgement (error: string | null, socketWrappe...
method onCacheRequestError (line 350) | private onCacheRequestError (error: string) {
method onCacheSetResponse (line 362) | private onCacheSetResponse (error: string | null, socketWrapper?: Sock...
method onStorageSetResponse (line 400) | private onStorageSetResponse (error: string | null, socketWrapper?: So...
method sendWriteAcknowledgementErrors (line 417) | private sendWriteAcknowledgementErrors (errorMessage: string) {
method onFatalError (line 432) | private onFatalError (error: string): void {
FILE: src/handlers/rpc/rpc-handler.ts
type RpcData (line 7) | interface RpcData {
class RpcHandler (line 13) | class RpcHandler extends Handler<RPCMessage> {
method constructor (line 20) | constructor (private config: DeepstreamConfig, private services: Deeps...
method handle (line 36) | public handle (socketWrapper: SocketWrapper, message: RPCMessage, orig...
method getAlternativeProvider (line 111) | public getAlternativeProvider (rpcName: string, correlationId: string)...
method makeRpc (line 154) | private makeRpc (socketWrapper: SimpleSocketWrapper, message: RPCMessa...
method makeRemoteRpc (line 198) | public makeRemoteRpc (requestor: SimpleSocketWrapper, message: RPCMess...
method onRemoteRPCMessage (line 240) | private onRemoteRPCMessage (msg: RPCMessage, originServerName: string)...
method onRPCDestroyed (line 271) | public onRPCDestroyed (correlationId: string): void {
FILE: src/handlers/rpc/rpc-proxy.ts
class RpcProxy (line 9) | class RpcProxy implements SimpleSocketWrapper {
method constructor (line 16) | constructor (config: DeepstreamConfig, private services: DeepstreamSer...
method sendAckMessage (line 19) | public sendAckMessage (message: RPCMessage): void {
method sendMessage (line 29) | public sendMessage (msg: RPCMessage): void {
method sendError (line 38) | public sendError (msg: RPCMessage, type: RPC_ACTION, errorMessage: str...
method parseMessage (line 47) | public parseMessage (serializedMessage: any): ParseResult[] {
FILE: src/handlers/rpc/rpc.ts
class Rpc (line 11) | class Rpc {
method constructor (line 21) | constructor (private rpcHandler: RpcHandler, private requestor: Simple...
method getRequestor (line 29) | private getRequestor (requestor: SimpleSocketWrapper): any {
method handle (line 59) | public handle (message: RPCMessage): void {
method destroy (line 83) | public destroy (): void {
method setProvider (line 99) | private setProvider (provider: SimpleSocketWrapper): void {
method handleAccept (line 114) | private handleAccept (message: RPCMessage) {
method reroute (line 138) | public reroute (): void {
method onAcceptTimeout (line 159) | private onAcceptTimeout (): void {
method onResponseTimeout (line 173) | public onResponseTimeout (): void {
FILE: src/jif/jif-handler.ts
type JifInMessage (line 26) | type JifInMessage = any
function getJifToMsg (line 29) | function getJifToMsg () {
constant TYPE (line 182) | const TYPE = { ACK: 'A', NORMAL: 'N' }
function getMsgToJif (line 184) | function getMsgToJif () {
class JIFHandler (line 286) | class JIFHandler {
method constructor (line 291) | constructor (private services: DeepstreamServices) {}
method fromJIF (line 296) | public fromJIF (jifMessage: JifInMessage) {
method toJIF (line 338) | public toJIF (message: Message): JifMessage {
method errorToJIF (line 356) | public errorToJIF (message: Message, event: ALL_ACTIONS | string) {
FILE: src/listen/listener-registry.ts
type ListenInProgress (line 5) | interface ListenInProgress {
class ListenerRegistry (line 10) | class ListenerRegistry implements SubscriptionListener {
method constructor (line 43) | constructor (private topic: TOPIC, private config: DeepstreamConfig, p...
method close (line 90) | public async close () {
method hasActiveProvider (line 98) | public hasActiveProvider (susbcriptionName: string): boolean {
method handle (line 111) | public handle (socketWrapper: SocketWrapper, message: ListenMessage): ...
method onIncomingMessage (line 133) | private onIncomingMessage (message: ListenMessage, serverName: string)...
method processResponseForListenInProgress (line 149) | private processResponseForListenInProgress (socketWrapper: SocketWrapp...
method onFirstSubscriptionMade (line 172) | public onFirstSubscriptionMade (subscriptionName: string): void {
method onSubscriptionMade (line 176) | public onSubscriptionMade (subscriptionName: string, socketWrapper: So...
method onLastSubscriptionRemoved (line 183) | public onLastSubscriptionRemoved (subscriptionName: string): void {
method onSubscriptionRemoved (line 200) | public onSubscriptionRemoved (subscriptionName: string, socketWrapper:...
method accept (line 206) | private accept (socketWrapper: SocketWrapper, message: ListenMessage):...
method addListener (line 225) | private addListener (socketWrapper: SocketWrapper, message: ListenMess...
method reconcileSubscriptionsToPatterns (line 244) | private reconcileSubscriptionsToPatterns (pattern: string, socketWrapp...
method removeListenerIfActive (line 275) | private removeListenerIfActive (pattern: string, socketWrapper: Socket...
method removeActiveListener (line 294) | private removeActiveListener (subscriptionName: string): void {
method startProviderSearch (line 303) | private startProviderSearch (subscriptionName: string): void {
method startLocalDiscoveryStage (line 328) | private startLocalDiscoveryStage (subscriptionName: string, localListe...
method triggerNextProvider (line 341) | private triggerNextProvider (subscriptionName: string, localListenArra...
method stopProviderSearch (line 388) | private stopProviderSearch (subscriptionName: string): void {
method onRecordStartProvided (line 420) | private onRecordStartProvided (subscriptionName: string): void {
method onRecordStopProvided (line 427) | private onRecordStopProvided (subscriptionName: string): void {
method addPattern (line 443) | private addPattern (pattern: string): void {
method removePattern (line 452) | private removePattern (pattern: string, socketWrapper: SocketWrapper):...
method removeLastPattern (line 457) | private removeLastPattern (pattern: string): void {
method removeListenerFromInProgress (line 464) | private removeListenerFromInProgress (listensCurrentlyInProgress: Map<...
method sendHasProviderUpdateToSingleSubscriber (line 478) | private sendHasProviderUpdateToSingleSubscriber (hasProvider: boolean,...
method sendHasProviderUpdate (line 491) | private sendHasProviderUpdate (hasProvider: boolean, subscriptionName:...
method sendSubscriptionForPatternFound (line 505) | private sendSubscriptionForPatternFound (provider: Provider, subscript...
method sendSubscriptionForPatternRemoved (line 517) | private sendSubscriptionForPatternRemoved (provider: Provider, subscri...
method createLocalListenArray (line 529) | private createLocalListenArray (subscriptionName: string): Provider[] {
method validatePattern (line 547) | private validatePattern (socketWrapper: SocketWrapper, message: Listen...
method getUniqueLockName (line 564) | private getUniqueLockName (subscriptionName: string) {
FILE: src/listen/listener-test-utils.ts
class ListenerTestUtils (line 12) | class ListenerTestUtils {
method constructor (line 30) | constructor (listenerTopic?: TOPIC.RECORD | TOPIC.EVENT) {
method complete (line 83) | public complete () {
method providerListensTo (line 100) | public providerListensTo (provider: number, pattern: string): void {
method providerUnlistensTo (line 117) | public providerUnlistensTo (provider: number, pattern: string) {
method providerWillGetListenTimeout (line 134) | public providerWillGetListenTimeout (provider: number, subscription: s...
method providerWillGetSubscriptionFound (line 145) | public providerWillGetSubscriptionFound (provider: number, pattern: st...
method providerWillGetSubscriptionRemoved (line 157) | public providerWillGetSubscriptionRemoved (provider: number, pattern: ...
method providerAcceptsButIsntAcknowledged (line 169) | public providerAcceptsButIsntAcknowledged (provider: number, pattern: ...
method providerAccepts (line 173) | public providerAccepts (provider: number, pattern: string, subscriptio...
method providerRejectsAndPreviousTimeoutProviderThatAcceptedIsUsed (line 183) | public providerRejectsAndPreviousTimeoutProviderThatAcceptedIsUsed (pr...
method providerAcceptsAndIsSentSubscriptionRemoved (line 187) | public providerAcceptsAndIsSentSubscriptionRemoved (provider: number, ...
method providerRejects (line 192) | public providerRejects (provider: number, pattern: string, subscriptio...
method acceptMessageThrowsError (line 205) | public acceptMessageThrowsError (provider: number, pattern: string, su...
method rejectMessageThrowsError (line 215) | public rejectMessageThrowsError (provider: number, pattern: string, su...
method providerLosesItsConnection (line 227) | public providerLosesItsConnection (provider: number) {
method subscriptionAlreadyMadeFor (line 234) | public subscriptionAlreadyMadeFor (subscriptionName: string) {
method clientSubscribesTo (line 238) | public clientSubscribesTo (client: number, subscriptionName: string, f...
method clientUnsubscribesTo (line 247) | public clientUnsubscribesTo (client: number, subscriptionName: string,...
method clientWillRecievePublishedUpdate (line 256) | public clientWillRecievePublishedUpdate (client: number, subscription:...
method publishUpdateWillBeSentToSubscribers (line 267) | public publishUpdateWillBeSentToSubscribers (subscription: string, sta...
method subscriptionHasActiveProvider (line 278) | public subscriptionHasActiveProvider (subscription: string, value: str...
FILE: src/plugins/heap-snapshot/heap-snapshot.ts
type HeapSnapshotOptions (line 5) | interface HeapSnapshotOptions {
class HeapSnapshot (line 14) | class HeapSnapshot extends DeepstreamPlugin {
method constructor (line 19) | constructor (private options: HeapSnapshotOptions, private services: R...
method init (line 23) | public init () {
method whenReady (line 38) | public async whenReady (): Promise<void> {
method close (line 42) | public async close (): Promise<void> {
method outputHeapSnapshot (line 46) | private outputHeapSnapshot () {
FILE: src/service/daemon.ts
function _start (line 6) | function _start (options: any) {
FILE: src/service/service.ts
function hasSystemD (line 12) | function hasSystemD () {
function hasSystemV (line 20) | function hasSystemV () {
function deleteSystemD (line 27) | async function deleteSystemD (name: string, callback: Function) {
function setupSystemD (line 53) | async function setupSystemD (name: string, options: any, callback: Funct...
function deleteSystemV (line 89) | async function deleteSystemV (name: string, callback: Function) {
function setupSystemV (line 113) | async function setupSystemV (name: string, options: any, callback: Funct...
FILE: src/services/authentication/combine/combine-authentication.ts
class CombineAuthentication (line 9) | class CombineAuthentication extends DeepstreamPlugin implements Deepstre...
method constructor (line 12) | constructor (private auths: DeepstreamAuthentication[]) {
method whenReady (line 21) | public async whenReady () {
method close (line 25) | public async close () {
method isValidUser (line 29) | public async isValidUser (connectionData: JSONObject, authData: JSONOb...
method onClientDisconnect (line 40) | public onClientDisconnect (userId: string): void {
FILE: src/services/authentication/file/file-based-authentication.ts
type FileAuthConfig (line 4) | interface FileAuthConfig {
class FileBasedAuthentication (line 21) | class FileBasedAuthentication extends DeepstreamPlugin implements Deepst...
method constructor (line 33) | constructor (private settings: FileAuthConfig, private services: Deeps...
method whenReady (line 42) | public async whenReady (): Promise<void> {
method isValidUser (line 48) | public async isValidUser (connectionData: any, authData: any) {
method validateSettings (line 94) | private validateSettings (settings: FileAuthConfig) {
FILE: src/services/authentication/http/http-authentication.ts
type HttpAuthenticationHandlerSettings (line 6) | interface HttpAuthenticationHandlerSettings {
class HttpAuthentication (line 26) | class HttpAuthentication extends DeepstreamPlugin implements DeepstreamA...
method constructor (line 31) | constructor (private settings: HttpAuthenticationHandlerSettings, priv...
method isValidUser (line 42) | public async isValidUser (connectionData: JSONObject, authData: JSONOb...
method validate (line 48) | private validate (id: number, connectionData: JSONObject, authData: JS...
method retry (line 128) | private retry (id: number, connectionData: JSONObject, authData: JSONO...
method validateSettings (line 159) | private validateSettings (): void {
FILE: src/services/authentication/open/open-authentication.ts
constant OPEN (line 7) | const OPEN: string = 'open'
class OpenAuthentication (line 14) | class OpenAuthentication extends DeepstreamPlugin implements DeepstreamA...
method isValidUser (line 20) | public async isValidUser (connectionData: JSONObject, authData: JSONOb...
FILE: src/services/authentication/storage/storage-based-authentication.ts
constant STRING (line 6) | const STRING = 'string'
type StorageAuthConfig (line 8) | interface StorageAuthConfig {
type UserData (line 23) | type UserData = DeepstreamAuthenticationResult & {
class StorageBasedAuthentication (line 29) | class StorageBasedAuthentication extends DeepstreamPlugin implements Dee...
method constructor (line 43) | constructor (private settings: StorageAuthConfig, private services: De...
method whenReady (line 50) | public async whenReady (): Promise<void> {
method isValidUser (line 57) | public async isValidUser (connectionData: any, authData: any): Promise...
FILE: src/services/cache/local-cache.ts
class LocalCache (line 4) | class LocalCache extends DeepstreamPlugin implements DeepstreamCache {
method head (line 9) | public head (recordName: string, callback: StorageHeadCallback) {
method headBulk (line 14) | public headBulk (recordNames: string[], callback: StorageHeadBulkCallb...
method set (line 28) | public set (key: string, version: number, data: any, callback: Storage...
method get (line 33) | public get (key: string, callback: StorageReadCallback) {
method delete (line 42) | public delete (key: string, callback: StorageWriteCallback) {
method deleteBulk (line 47) | public deleteBulk (keys: string[], callback: StorageWriteCallback) {
FILE: src/services/cluster-node/single-cluster-node.ts
class SingleClusterNode (line 4) | class SingleClusterNode extends DeepstreamPlugin implements DeepstreamCl...
method sendDirect (line 7) | public sendDirect (serverName: string, message: Message, metaData?: an...
method send (line 9) | public send (message: Message, metaData?: any) {}
method subscribe (line 11) | public subscribe (stateRegistryTopic: TOPIC, callback: Function) {}
method close (line 13) | public async close (): Promise<void> {}
FILE: src/services/cluster-node/vertical-cluster-node.ts
class VerticalClusterNode (line 17) | class VerticalClusterNode extends DeepstreamPlugin implements Deepstream...
method constructor (line 23) | constructor (pluginConfig: any, private services: DeepstreamServices, ...
method init (line 27) | public init () {
method whenReady (line 46) | async whenReady (): Promise<void> {
method send (line 50) | public send (message: Message, metaData?: any): void {
method sendDirect (line 54) | public sendDirect (serverName: string, message: Message, metaData?: an...
method subscribe (line 58) | public subscribe<SpecificMessage> (stateRegistryTopic: TOPIC, callback...
method close (line 69) | public async close (): Promise<void> {
FILE: src/services/cluster-registry/distributed-cluster-registry.ts
class DistributedClusterRegistry (line 12) | class DistributedClusterRegistry extends DeepstreamPlugin implements Clu...
method constructor (line 27) | constructor (private pluginOptions: any, private services: Readonly<De...
method init (line 32) | public init () {
method close (line 49) | public async close (): Promise<void> {
method onServerAdded (line 56) | public onServerAdded (callback: (serverName: string) => void) {
method onServerRemoved (line 60) | public onServerRemoved (callback: (serverName: string) => void) {
method getAll (line 67) | public getAll (): string[] {
method isLeader (line 74) | public isLeader (): boolean {
method getLeader (line 81) | public getLeader () {
method onMessage (line 98) | private onMessage (message: ClusterMessage) {
method checkNodes (line 119) | private checkNodes () {
method updateNode (line 137) | private updateNode (message: ClusterMessage) {
method removeNode (line 158) | private removeNode (serverName: string) {
method publishStatus (line 170) | private publishStatus (): void {
method leaveCluster (line 188) | private leaveCluster () {
FILE: src/services/cluster-registry/distributed-state-registry-factory.ts
class DistributedStateRegistryFactory (line 5) | class DistributedStateRegistryFactory extends DeepstreamPlugin implement...
method constructor (line 9) | constructor (private pluginConfig: DistributedStateRegistryOptions, pr...
method getStateRegistries (line 22) | public getStateRegistries (): Map<TOPIC, StateRegistry> {
FILE: src/services/cluster-state/distributed-state-registry-factory.ts
class DistributedStateRegistryFactory (line 5) | class DistributedStateRegistryFactory extends DeepstreamPlugin implement...
method constructor (line 9) | constructor (private pluginConfig: DistributedStateRegistryOptions, pr...
method getStateRegistries (line 22) | public getStateRegistries (): Map<TOPIC, StateRegistry> {
FILE: src/services/cluster-state/distributed-state-registry.ts
type DistributedStateRegistryOptions (line 6) | type DistributedStateRegistryOptions = any
class DistributedStateRegistry (line 17) | class DistributedStateRegistry implements StateRegistry {
method constructor (line 34) | constructor (private topic: TOPIC, private stateOptions: any, private ...
method whenReady (line 55) | public async whenReady () {
method onAdd (line 61) | public onAdd (callback: StateRegistryCallback): void {
method onRemove (line 65) | public onRemove (callback: StateRegistryCallback): void {
method has (line 72) | public has (name: string) {
method add (line 80) | public add (name: string) {
method remove (line 94) | public remove (name: string) {
method removeAll (line 105) | public removeAll (serverName: string): void {
method onServerAdded (line 112) | public onServerAdded (serverName: string) {
method onServerRemoved (line 120) | public onServerRemoved (serverName: string) {
method getAllServers (line 131) | public getAllServers (name: string) {
method getAll (line 142) | public getAll (serverName: string): string[] {
method removeFromServer (line 160) | private removeFromServer (name: string, serverName: string) {
method addToServer (line 181) | private addToServer (name: string, serverName: string) {
method sendMessage (line 202) | private sendMessage (name: string, action: STATE_ACTION) {
method getCheckSumTotal (line 224) | private getCheckSumTotal (serverName: string, callback: (checksum: num...
method createCheckSum (line 251) | private createCheckSum (name: string) {
method verifyCheckSum (line 274) | private verifyCheckSum (serverName: string, remoteCheckSum: number) {
method _requestFullState (line 298) | private _requestFullState (serverName: string) {
method sendFullState (line 315) | public sendFullState (serverName: string): void {
method applyFullState (line 339) | private applyFullState (serverName: string, names: string[]) {
method resetFullStateSent (line 367) | private resetFullStateSent (): void {
method processIncomingMessage (line 375) | private processIncomingMessage (message: StateMessage, serverName: str...
FILE: src/services/cluster-state/single-state-registry.ts
class SingleStateRegistry (line 8) | class SingleStateRegistry extends DeepstreamPlugin implements StateRegis...
method has (line 16) | public has (name: string): boolean {
method onAdd (line 20) | public onAdd (callback: StateRegistryCallback): void {
method onRemove (line 24) | public onRemove (callback: StateRegistryCallback): void {
method add (line 32) | public add (name: string): void {
method remove (line 46) | public remove (name: string): void {
method getAll (line 59) | public getAll (): string[] {
method getAllServers (line 66) | public getAllServers (subscriptionName: string): string[] {
method removeAll (line 74) | public removeAll (serverName: string): void {
FILE: src/services/http/node/node-http.ts
type NodeHTTPInterface (line 13) | interface NodeHTTPInterface {
class NodeHTTP (line 29) | class NodeHTTP extends DeepstreamPlugin implements DeepstreamHTTPService {
method constructor (line 52) | constructor (private pluginOptions: NodeHTTPInterface, private service...
method whenReady (line 67) | public async whenReady (): Promise<void> {
method close (line 92) | public async close (): Promise<void> {
method sendWebsocketMessage (line 107) | public sendWebsocketMessage (socket: WebSocket, message: any, isBinary...
method getSocketWrappersForUserId (line 117) | public getSocketWrappersForUserId (userId: string) {
method registerPostPathPrefix (line 121) | public registerPostPathPrefix<DataInterface> (prefix: string, handler:...
method registerGetPathPrefix (line 126) | public registerGetPathPrefix (prefix: string, handler: GetRequestHandl...
method registerWebsocketEndpoint (line 131) | public registerWebsocketEndpoint (path: string, createSocketWrapper: S...
method createHttpServer (line 169) | private createHttpServer () {
method onUpgrade (line 180) | private onUpgrade (
method onRequest (line 201) | private onRequest (
method handlePost (line 232) | private handlePost (request: http.IncomingMessage, response: http.Serv...
method handleGet (line 272) | private handleGet (request: http.IncomingMessage, response: http.Serve...
method handleOptions (line 285) | private handleOptions (
method verifyOrigin (line 333) | private verifyOrigin (
method terminateResponse (line 368) | private terminateResponse (response: http.ServerResponse, code: number...
method sendResponse (line 378) | private sendResponse (
FILE: src/services/http/uws/uws-http.ts
type UWSHTTPInterface (line 8) | interface UWSHTTPInterface extends uws.AppOptions {
type UserData (line 20) | interface UserData {
class UWSHTTP (line 26) | class UWSHTTP extends DeepstreamPlugin implements DeepstreamHTTPService {
method constructor (line 41) | constructor (private pluginOptions: UWSHTTPInterface, private services...
method whenReady (line 73) | public async whenReady (): Promise<void> {
method close (line 118) | public async close (): Promise<void> {
method registerPostPathPrefix (line 132) | public registerPostPathPrefix<DataInterface> (prefix: string, handler:...
method registerGetPathPrefix (line 170) | public registerGetPathPrefix (prefix: string, handler: GetRequestHandl...
method sendWebsocketMessage (line 197) | public sendWebsocketMessage (socket: uws.WebSocket<UserData>, message:...
method getSocketWrappersForUserId (line 206) | public getSocketWrappersForUserId (userId: string) {
method registerWebsocketEndpoint (line 210) | public registerWebsocketEndpoint (path: string, createSocketWrapper: S...
method terminateResponse (line 260) | private terminateResponse (response: uws.HttpResponse, code: number, m...
method sendResponse (line 280) | private sendResponse (
method getHeaders (line 307) | public getHeaders (req: uws.HttpRequest) {
method getSLLParams (line 314) | private getSLLParams (options: any) {
method getVerifiedOriginHeaders (line 338) | private getVerifiedOriginHeaders (response: uws.HttpResponse, request:...
method handleOptions (line 374) | private handleOptions (response: uws.HttpResponse, request: uws.HttpRe...
function readJson (line 429) | function readJson (res: uws.HttpResponse, cb: Function, err: (code: numb...
FILE: src/services/lock/distributed-lock-registry.ts
class DistributedLockRegistry (line 15) | class DistributedLockRegistry extends DeepstreamPlugin implements Deepst...
method constructor (line 26) | constructor (private pluginOptions: any, private services: Readonly<De...
method init (line 31) | public init () {
method get (line 39) | public get (lockName: string, callback: LockCallback) {
method release (line 52) | public release (lockName: string) {
method getRemoteLock (line 64) | private getRemoteLock (lockName: string, callback: LockCallback) {
method releaseRemoteLock (line 84) | private releaseRemoteLock (lockName: string) {
method onPrivateMessage (line 98) | private onPrivateMessage (message: LockMessage, remoteServerName: stri...
method handleRemoteLockRequest (line 126) | private handleRemoteLockRequest (lockName: string, remoteServerName: s...
method handleRemoteLockResponse (line 138) | private handleRemoteLockResponse (lockName: string, result: boolean) {
method getLock (line 147) | private getLock (lockName: string) {
method releaseLock (line 168) | private releaseLock (lockName: string) {
method onLockTimeout (line 177) | private onLockTimeout (lockName: string) {
method onLockRequestTimeout (line 186) | private onLockRequestTimeout (lockName: string) {
FILE: src/services/logger/pino/pino-logger.ts
class PinoLogger (line 13) | class PinoLogger extends DeepstreamPlugin implements DeepstreamLogger {
method constructor (line 17) | constructor (pluginOptions: LoggerOptions, private services: Deepstrea...
method shouldLog (line 27) | public shouldLog (logLevel: LOG_LEVEL): boolean {
method setLogLevel (line 35) | public setLogLevel (logLevel: LOG_LEVEL): void {
method info (line 42) | public info (event: EVENT, message?: string, metaData?: any): void {
method debug (line 53) | public debug (event: EVENT, message?: string, metaData?: any): void {
method warn (line 64) | public warn (event: EVENT, message?: string, metaData?: any): void {
method error (line 75) | public error (event: EVENT, message?: string, metaData?: any): void {
method fatal (line 87) | public fatal (event: EVENT, message?: string, metaData?: any): void {
method getNameSpace (line 101) | public getNameSpace (namespace: string): NamespacedLogger {
method log (line 112) | private log (logLevel: pino.LevelWithSilent, namespace: string, event:...
FILE: src/services/logger/std/std-out-logger.ts
class StdOutLogger (line 5) | class StdOutLogger extends DeepstreamPlugin implements DeepstreamLogger {
method constructor (line 24) | constructor (private options: any = {}, private services: DeepstreamSe...
method whenReady (line 30) | public async whenReady (): Promise<void> {
method shouldLog (line 34) | public shouldLog (logLevel: number): boolean {
method debug (line 38) | public debug (event: EVENT, logMessage: string): void {
method info (line 42) | public info (event: EVENT, logMessage: string): void {
method warn (line 46) | public warn (event: EVENT, logMessage: string, metaData?: MetaData): v...
method error (line 50) | public error (event: EVENT, logMessage: string, metaData?: MetaData): ...
method fatal (line 54) | public fatal (event: EVENT, logMessage: string, metaData?: MetaData): ...
method getNameSpace (line 59) | public getNameSpace (namespace: string): NamespacedLogger {
method setLogLevel (line 73) | public setLogLevel (logLevel: LOG_LEVEL) {
method log (line 80) | private log (logLevel: LOG_LEVEL, namespace: string, event: EVENT, log...
FILE: src/services/monitoring/combine-monitoring.ts
class CombineMonitoring (line 8) | class CombineMonitoring extends DeepstreamPlugin implements DeepstreamMo...
method constructor (line 11) | constructor (private monitorings: DeepstreamMonitoring[]) {
method whenReady (line 20) | public async whenReady () {
method close (line 24) | public async close () {
method init (line 28) | public init () {
method onErrorLog (line 32) | public onErrorLog (loglevel: LOG_LEVEL, event: EVENT, logMessage: stri...
method onLogin (line 37) | public onLogin (allowed: boolean, endpointType: string): void {
method onMessageReceived (line 41) | public onMessageReceived (message: Message, socketData: SocketData): v...
method onMessageSend (line 45) | public onMessageSend (message: Message): void {
method onBroadcast (line 49) | public onBroadcast (message: Message, count: number): void {
FILE: src/services/monitoring/http/monitoring-http.ts
type HTTPMonitoringOptions (line 4) | interface HTTPMonitoringOptions {
class HTTPMonitoring (line 11) | class HTTPMonitoring extends MonitoringBase {
method constructor (line 15) | constructor (private pluginOptions: HTTPMonitoringOptions, services: D...
method whenReady (line 28) | public async whenReady (): Promise<void> {
method close (line 52) | public async close (): Promise<void> {
FILE: src/services/monitoring/log/monitoring-log.ts
type HTTPMonitoringOptions (line 4) | interface HTTPMonitoringOptions {
class LogMonitoring (line 9) | class LogMonitoring extends MonitoringBase {
method constructor (line 14) | constructor (private pluginOptions: HTTPMonitoringOptions, services: D...
method whenReady (line 22) | public async whenReady (): Promise<void> {
method close (line 35) | public async close (): Promise<void> {
FILE: src/services/monitoring/monitoring-base.ts
method constructor (line 14) | constructor (protected services: DeepstreamServices) {
method onErrorLog (line 18) | public onErrorLog (loglevel: LOG_LEVEL, event: EVENT, logMessage: string...
method onLogin (line 32) | public onLogin (allowed: boolean, endpointType: string): void {
method onMessageReceived (line 41) | public onMessageReceived (message: Message): void {
method onMessageSend (line 51) | public onMessageSend (message: Message): void {
method onBroadcast (line 61) | public onBroadcast (message: Message, count: number): void {
method getAndResetMonitoringStats (line 71) | public getAndResetMonitoringStats () {
method getStateMetrics (line 87) | private getStateMetrics () {
FILE: src/services/monitoring/noop-monitoring.ts
class NoopMonitoring (line 4) | class NoopMonitoring extends DeepstreamPlugin implements DeepstreamMonit...
method onErrorLog (line 7) | public onErrorLog (loglevel: LOG_LEVEL, event: EVENT, logMessage: stri...
method onLogin (line 10) | public onLogin (allowed: boolean, endpointType: string): void {
method onMessageReceived (line 13) | public onMessageReceived (message: Message, socketData: SocketData): v...
method onMessageSend (line 16) | public onMessageSend (message: Message): void {
method onBroadcast (line 19) | public onBroadcast (message: Message, count: number): void {
FILE: src/services/permission/open/open-permission.ts
class OpenPermission (line 8) | class OpenPermission extends DeepstreamPlugin implements DeepstreamPermi...
method canPerformAction (line 14) | public canPerformAction (socketWrapper: SocketWrapper, message: Messag...
FILE: src/services/permission/valve/config-compiler.ts
function compileRuleset (line 30) | function compileRuleset (path: string, rules: any) {
FILE: src/services/permission/valve/config-permission.ts
constant UNDEFINED (line 10) | const UNDEFINED = 'undefined'
type RuleType (line 12) | type RuleType = string
type ValveSection (line 13) | type ValveSection = string
class ConfigPermission (line 15) | class ConfigPermission extends DeepstreamPlugin implements DeepstreamPer...
method constructor (line 32) | constructor (private permissionOptions: ValveConfig, private services:...
method whenReady (line 43) | public async whenReady (): Promise<void> {
method close (line 46) | public async close () {
method setRecordHandler (line 53) | public setRecordHandler (recordHandler: RecordHandler): void {
method useConfig (line 64) | public useConfig (permissions: ValveSchema): void {
method canPerformAction (line 88) | public canPerformAction (socketWrapper: SocketWrapper, message: Messag...
method getCompiledRulesForName (line 129) | private getCompiledRulesForName (name: string, ruleSpecification: any)...
FILE: src/services/permission/valve/config-schema.ts
constant SCHEMA (line 3) | const SCHEMA: ConfigSchema = {
FILE: src/services/permission/valve/path-parser.ts
constant WILDCARD_REGEXP (line 1) | const WILDCARD_REGEXP = /\*/g
constant WILDCARD_STRING (line 2) | const WILDCARD_STRING = '.*'
constant VARIABLE_REGEXP (line 3) | const VARIABLE_REGEXP = /(\$[a-zA-Z0-9]+)/g
constant VARIABLE_STRING (line 4) | const VARIABLE_STRING = '([^/]+)'
constant INVALID_VARIABLE_REGEXP (line 5) | const INVALID_VARIABLE_REGEXP = /(\$[^a-zA-Z0-9])/
FILE: src/services/permission/valve/rule-application.ts
constant OPEN (line 8) | const OPEN = 'open'
constant LOADING (line 9) | const LOADING = 'loading'
constant ERROR (line 10) | const ERROR = 'error'
constant UNDEFINED (line 12) | const UNDEFINED = 'undefined'
constant STRING (line 13) | const STRING = 'string'
type RuleApplicationParams (line 15) | interface RuleApplicationParams {
class RuleApplication (line 35) | class RuleApplication {
method constructor (line 53) | constructor (private params: RuleApplicationParams) {
method run (line 72) | private run (): void {
method onRuleError (line 111) | private onRuleError (error: string): void {
method onLoadComplete (line 126) | private onLoadComplete (recordName: string, version: number, data: any...
method onLoadError (line 139) | private onLoadError (event: any, errorMessage: string, recordName: str...
method destroy (line 151) | private destroy () {
method getCurrentData (line 176) | private getCurrentData (): any {
method getRecordPatchData (line 210) | private getRecordPatchData (msg: RecordWriteMessage): any {
method getOldData (line 247) | private getOldData (): any {
method getArguments (line 263) | private getArguments (): any[] {
method getUser (line 279) | private getUser (): any {
method getPathVars (line 295) | private getPathVars (): string[] {
method isReady (line 311) | private isReady (): boolean {
method loadRecord (line 331) | private loadRecord (recordName: string): void {
method createNewRecordRequest (line 356) | private createNewRecordRequest (recordName: string): void {
method crossReference (line 374) | private crossReference (recordName: string): any | null {
FILE: src/services/permission/valve/rule-cache.ts
type CachedRule (line 3) | interface CachedRule {
class RuleCache (line 8) | class RuleCache {
method constructor (line 16) | constructor (config: ValveConfig) {
method close (line 20) | public close () {
method reset (line 27) | public reset (): void {
method has (line 35) | public has (section: string, name: string, type: string): boolean {
method get (line 42) | public get (section: string, name: string, type: string): string | und...
method set (line 54) | public set (section: string, name: string, type: string, rule: string)...
method purge (line 69) | private purge () {
function toKey (line 83) | function toKey (section: string, name: string, type: string): string {
FILE: src/services/permission/valve/rule-parser.ts
constant FUNCTION_REGEXP (line 5) | const FUNCTION_REGEXP = /([\w]+(?:['"`]\])?)\s*\(/g
constant USER_FUNCTION_REGEXP (line 6) | const USER_FUNCTION_REGEXP = /[^\w$]function[^\w$]|=>/g
constant NEW_REGEXP (line 7) | const NEW_REGEXP = /(^|[^\w$])new[^\w$]/
constant OLD_DATA_REGEXP (line 8) | const OLD_DATA_REGEXP = /(^|[^\w~])oldData[^\w~]/
constant DATA_REGEXP (line 9) | const DATA_REGEXP = /(^|[^\w.~])data($|[^\w~])/
constant SUPPORTED_FUNCTIONS (line 11) | const SUPPORTED_FUNCTIONS = [
FILE: src/services/permission/valve/rules-map.ts
type RuleType (line 4) | interface RuleType { name: string, data: boolean, oldData: boolean }
constant RULE_TYPES (line 11) | const RULE_TYPES: Dictionary<RuleType> = {
constant RULES_MAP (line 38) | const RULES_MAP: Dictionary<{ section: string, actions: Dictionary<RuleT...
FILE: src/services/storage/noop-storage.ts
class NoopStorage (line 3) | class NoopStorage extends DeepstreamPlugin implements DeepstreamStorage {
method set (line 6) | public set (key: string, version: number, data: any, callback: Storage...
method get (line 10) | public get (key: string, callback: StorageReadCallback) {
method delete (line 14) | public delete (key: string, callback: StorageWriteCallback) {
method deleteBulk (line 18) | public deleteBulk (key: string[], callback: StorageWriteCallback) {
FILE: src/services/subscription-registry/default-subscription-registry-factory.ts
class DefaultSubscriptionRegistryFactory (line 5) | class DefaultSubscriptionRegistryFactory extends DeepstreamPlugin implem...
method constructor (line 10) | constructor (private pluginOptions: any, private services: Readonly<De...
method getSubscriptionRegistry (line 14) | public getSubscriptionRegistry (topic: TOPIC, clusterTopic: TOPIC) {
method getSubscriptionRegistries (line 23) | public getSubscriptionRegistries () {
FILE: src/services/subscription-registry/default-subscription-registry.ts
type SubscriptionActions (line 14) | interface SubscriptionActions {
type Subscription (line 21) | interface Subscription {
class DefaultSubscriptionRegistry (line 26) | class DefaultSubscriptionRegistry implements SubscriptionRegistry {
method constructor (line 40) | constructor (private pluginConfig: any, private services: Readonly<Dee...
method whenReady (line 78) | public async whenReady () {
method close (line 82) | public async close () {
method getAllServers (line 89) | public getAllServers (subscriptionName: string): string[] {
method getAllRemoteServers (line 97) | public getAllRemoteServers (subscriptionName: string): string[] {
method getNames (line 110) | public getNames (): string[] {
method hasName (line 118) | public hasName (subscriptionName: string): boolean {
method setAction (line 128) | public setAction (name: string, value: EVENT_ACTION | RECORD_ACTION | ...
method sendToSubscribers (line 137) | public sendToSubscribers (name: string, message: Message, noDelay: boo...
method subscribeBulk (line 173) | public subscribeBulk (message: BulkSubscriptionMessage, socket: Socket...
method unsubscribeBulk (line 190) | public unsubscribeBulk (message: BulkSubscriptionMessage, socket: Sock...
method subscribe (line 206) | public subscribe (name: string, message: Message, socket: SocketWrappe...
method unsubscribe (line 244) | public unsubscribe (name: string, message: Message, socket: SocketWrap...
method getLocalSubscribers (line 282) | public getLocalSubscribers (name: string): Set<SocketWrapper> {
method hasLocalSubscribers (line 292) | public hasLocalSubscribers (name: string): boolean {
method setSubscriptionListener (line 299) | public setSubscriptionListener (listener: SubscriptionListener): void {
method addSocket (line 305) | private addSocket (subscription: Subscription, socket: SocketWrapper):...
method removeSocket (line 320) | private removeSocket (subscription: Subscription, socket: SocketWrappe...
method onSocketClose (line 346) | private onSocketClose (socket: SocketWrapper): void {
method illegalCleanup (line 363) | private illegalCleanup () {
FILE: src/services/telemetry/deepstreamio-telemetry.ts
constant TELEMETRY_URL (line 8) | const TELEMETRY_URL = process.env.TELEMETRY_URL || 'http://telemetry.dee...
constant DEFAULT_UUID (line 9) | const DEFAULT_UUID = '00000000-0000-0000-0000-000000000000'
type DeepstreamIOTelemetryOptions (line 11) | interface DeepstreamIOTelemetryOptions {
class DeepstreamIOTelemetry (line 17) | class DeepstreamIOTelemetry extends DeepstreamPlugin implements Deepstre...
method constructor (line 21) | constructor (private pluginOptions: DeepstreamIOTelemetryOptions, priv...
method init (line 25) | public init () {
method whenReady (line 42) | public async whenReady (): Promise<void> {
method close (line 79) | public async close (): Promise<void> {
method sendReport (line 82) | private sendReport (data: any): void {
FILE: src/test/helper/test-helper.ts
class PermissionHandler (line 72) | class PermissionHandler extends DeepstreamPlugin implements PermissionHa...
method constructor (line 78) | constructor () {
method canPerformAction (line 86) | public canPerformAction (socketWrapper: SocketWrapper, message: Messag...
class MonitoringMock (line 93) | class MonitoringMock extends DeepstreamPlugin implements DeepstreamMonit...
method onErrorLog (line 95) | public onErrorLog (loglevel: LOG_LEVEL, event: EVENT, logMessage: stri...
method onLogin (line 97) | public onLogin (allowed: boolean, endpointType: string): void {
method onMessageReceived (line 99) | public onMessageReceived (message: Message): void {
method onMessageSend (line 101) | public onMessageSend (message: Message): void {
method onBroadcast (line 103) | public onBroadcast (message: Message, count: number): void {
method get (line 114) | get (name, cb) { cb(true) }
method release (line 115) | release () {}
FILE: src/test/helper/test-http-server.ts
class TestHttpServer (line 4) | class TestHttpServer extends EventEmitter {
method constructor (line 13) | constructor (private port: number, private callback: Function, private...
method getRandomPort (line 19) | public static getRandomPort () {
method getRequestHeader (line 23) | public getRequestHeader (key: string) {
method reset (line 27) | public reset () {
method respondWith (line 33) | public respondWith (statusCode: number, data: any) {
method close (line 42) | public close (callback: Function) {
method onListen (line 46) | private onListen () {
method log (line 51) | private log (msg: string) {
method onRequest (line 57) | private onRequest (request: http.IncomingMessage, response: http.Outgo...
FILE: src/test/helper/test-mocks.ts
function getSocketWrapper (line 48) | function getSocketWrapper (userId: string, authData: JSONObject = {}, cl...
FILE: src/test/mock/authentication-handler-mock.ts
class AuthenticationMock (line 3) | class AuthenticationMock extends DeepstreamPlugin implements DeepstreamA...
method constructor (line 11) | constructor () {
method reset (line 16) | public reset () {
method isValidUser (line 24) | public async isValidUser (handshakeData: any, authData: any): Promise<...
method onClientDisconnect (line 52) | public onClientDisconnect (username: string) {
FILE: src/test/mock/http-mock.ts
class HttpServerMock (line 3) | class HttpServerMock extends EventEmitter {
method listen (line 9) | public listen (port: string, host: string, callback: Function) {
method close (line 22) | public close (callback: Function) {
method address (line 30) | public address () {
method _simulateUpgrade (line 37) | public _simulateUpgrade (socket: any) {
class HttpMock (line 54) | class HttpMock {
method constructor (line 56) | constructor () {
method createServer (line 60) | public createServer () {
FILE: src/test/mock/logger-mock.ts
class LoggerMock (line 4) | class LoggerMock extends DeepstreamPlugin implements DeepstreamLogger {
method constructor (line 12) | constructor () {
method shouldLog (line 22) | public shouldLog (logLevel: LOG_LEVEL): boolean {
method warn (line 26) | public warn (event: EVENT | string, message?: string, metaData?: any) {
method debug (line 31) | public debug (event: EVENT | string, message?: string, metaData?: any) {
method info (line 36) | public info (event: EVENT | string, message?: string, metaData?: any) {
method error (line 41) | public error (event: EVENT | string, message?: string, metaData?: any) {
method fatal (line 46) | public fatal (event: string, message?: string | undefined, metaData?: ...
method getNameSpace (line 51) | public getNameSpace (namespace: string): NamespacedLogger {
method log (line 55) | private log (level: LOG_LEVEL, event: EVENT | string, message?: string...
method setLogLevel (line 62) | public setLogLevel () {
FILE: src/test/mock/message-connector-mock.ts
class MessageConnectorMock (line 5) | class MessageConnectorMock extends DeepstreamPlugin implements Deepstrea...
method constructor (line 16) | constructor (private options: any) {
method reset (line 21) | public reset () {
method subscribe (line 31) | public subscribe <MessageType> (topic: TOPIC, callback: (message: Mess...
method sendBroadcast (line 36) | public sendBroadcast () {
method send (line 39) | public send (message: Message, metaData?: any) {
method sendDirect (line 45) | public sendDirect (serverName: string, message: Message) {
method unsubscribe (line 52) | public unsubscribe (topic: TOPIC, callback: (message: Message) => void) {
method simulateIncomingMessage (line 56) | public simulateIncomingMessage (topic: TOPIC, msg: Message, serverName...
method getAll (line 60) | public getAll () {
method isLeader (line 64) | public isLeader () {
method getLeader (line 68) | public getLeader () {
method getCurrentLeader (line 72) | public getCurrentLeader () {
method subscribeServerDisconnect (line 76) | public subscribeServerDisconnect () {
FILE: src/test/mock/permission-handler-mock.ts
class PermissionHandlerMock (line 4) | class PermissionHandlerMock extends DeepstreamPlugin {
method constructor (line 9) | constructor () {
method reset (line 14) | public reset () {
method canPerformAction (line 19) | public canPerformAction (socketWrapper: SocketWrapper, message: Messag...
FILE: src/test/mock/plugin-mock.ts
class PluginMock (line 4) | class PluginMock extends DeepstreamPlugin {
method constructor (line 9) | constructor (private options: any, services: DeepstreamServices, confi...
method setReady (line 13) | public setReady () {
method whenReady (line 18) | public async whenReady () {
FILE: src/test/mock/socket-mock.ts
class SocketMock (line 3) | class SocketMock {
method constructor (line 13) | constructor () {
method send (line 23) | public send (message: Message) {
method end (line 28) | public end () {
method getMsg (line 31) | public getMsg (i: number) {
method getMsgSize (line 35) | public getMsgSize () {
method close (line 39) | public close () {
method destroy (line 45) | public destroy () {
method doClose (line 49) | public doClose () {
FILE: src/test/mock/socket-wrapper-factory-mock.ts
class SocketWrapperMock (line 4) | class SocketWrapperMock extends EventEmitter {
method constructor (line 15) | constructor (private handshakeData: any) {
method sendAckMessage (line 19) | public sendAckMessage (message: Message) {
method getHandshakeData (line 23) | public getHandshakeData () {
method sendError (line 27) | public sendError (/* topic, type, msg */) {
method sendMessage (line 30) | public sendMessage (message: Message) {
method parseData (line 34) | public parseData (message: Message) {
method send (line 46) | public send (/* message */) {
method destroy (line 49) | public destroy () {
method close (line 55) | public close () {
method setUpHandshakeData (line 59) | public setUpHandshakeData () {
FILE: src/test/mock/storage-mock.ts
class StorageMock (line 4) | class StorageMock extends DeepstreamPlugin implements DeepstreamStorage,...
method constructor (line 22) | constructor () {
method reset (line 27) | public reset () {
method head (line 45) | public head (recordName: string, callback: any): void {
method headBulk (line 49) | public headBulk (recordNames: string[], callback: any): void {
method deleteBulk (line 53) | public deleteBulk (keys: string[], callback: StorageWriteCallback) {
method delete (line 71) | public delete (key: string, callback: StorageWriteCallback) {
method hadGetFor (line 89) | public hadGetFor (key: string) {
method triggerLastGetCallback (line 99) | public triggerLastGetCallback (errorMessage: string, value: JSONObject) {
method get (line 105) | public get (key: string, callback: StorageReadCallback) {
method set (line 123) | public set (key: string, version: number, value: JSONObject, callback:...
FILE: src/utils/dependency-initialiser.ts
class DependencyInitialiser (line 4) | class DependencyInitialiser {
method constructor (line 12) | constructor (private config: DeepstreamConfig, private services: Deeps...
method whenReady (line 34) | public async whenReady (): Promise<void> {
method getDependency (line 43) | public getDependency (): DeepstreamPlugin {
method onReady (line 50) | private onReady (): void {
method onTimeout (line 66) | private onTimeout (): void {
FILE: src/utils/json-path.ts
constant SPLIT_REG_EXP (line 1) | const SPLIT_REG_EXP = /[[\]]/g
function getValue (line 7) | function getValue (data: any, path: string): any {
function setValue (line 28) | function setValue (root: any, path: string, value: any): void {
function tokenize (line 56) | function tokenize (path: string): Array<string | number> {
FILE: src/utils/message-distributor.ts
class MessageDistributor (line 8) | class MessageDistributor {
method constructor (line 11) | constructor (options: DeepstreamConfig, private services: DeepstreamSe...
method distribute (line 17) | public distribute (socketWrapper: SocketWrapper, message: Message) {
method registerForTopic (line 37) | public registerForTopic (topic: TOPIC, callback: (message: Message) =>...
method onMessageConnectorMessage (line 54) | private onMessageConnectorMessage (callback: Function, message: Messag...
FILE: src/utils/message-processor.ts
class MessageProcessor (line 10) | class MessageProcessor {
method constructor (line 13) | constructor (config: DeepstreamConfig, private services: DeepstreamSer...
method onAuthenticatedMessage (line 23) | public onAuthenticatedMessage (socketWrapper: SocketWrapper, message: ...
method process (line 34) | public process (socketWrapper: SocketWrapper, parsedMessages: Message[...
method onBulkPermissionResponse (line 77) | private onBulkPermissionResponse (socketWrapper: SocketWrapper, messag...
method onPermissionResponse (line 100) | private onPermissionResponse (socketWrapper: SocketWrapper, message: M...
method processInvalidResponse (line 108) | private processInvalidResponse (socketWrapper: SocketWrapper, message:...
FILE: src/utils/utils.spec.ts
function _map (line 57) | function _map () {
function _schema (line 65) | function _schema () {
FILE: telemetry-server/telemetry-server.ts
function insertStats (line 10) | async function insertStats (stats: any) {
FILE: test-e2e/framework-v3/client-handler.ts
type E2EClient (line 5) | interface E2EClient {
function createClient (line 13) | function createClient (clientName: string, server: string, options?: any) {
function getClientNames (line 133) | function getClientNames (expression: string) {
function getClients (line 147) | function getClients (expression: string) {
function assertNoErrors (line 151) | function assertNoErrors (client: string) {
FILE: test-e2e/framework-v3/client.ts
method logsOut (line 17) | logsOut (clientExpression: string, done: Function) {
method connect (line 25) | connect (clientExpression: string, server: string) {
method connectAndLogin (line 31) | connectAndLogin (clientExpression: string, server: string, done: Functio...
method login (line 42) | login (clientExpression: string, username: string, password: string, don...
method attemptLogin (line 55) | attemptLogin (clientExpression: string, username: string, password: stri...
method receivedTooManyLoginAttempts (line 64) | receivedTooManyLoginAttempts (clientExpression: string) {
method recievesNoLoginResponse (line 73) | recievesNoLoginResponse (clientExpression: string) {
method recievesLoginResponse (line 79) | recievesLoginResponse (clientExpression: string, loginFailed: boolean, d...
method connectionTimesOut (line 97) | connectionTimesOut (clientExpression: string, done: Function) {
method receivedErrorOnce (line 108) | receivedErrorOnce (clientExpression: string, topicName: string, eventNam...
method receivedOneError (line 118) | receivedOneError (clientExpression: string, topicName: string, eventName...
method callbackCalled (line 132) | callbackCalled (clientExpression: string, eventName: string, notCalled: ...
method receivedNoErrors (line 152) | receivedNoErrors (clientExpression: string) {
method hadConnectionState (line 158) | hadConnectionState (clientExpression: string, had: boolean, state: boole...
FILE: test-e2e/framework-v3/event.ts
method received (line 6) | received (clientExpression: string, doesReceive: boolean, subscriptionNa...
method publishes (line 23) | publishes (clientExpression: string, subscriptionName: string, data: str...
method subscribes (line 29) | subscribes (clientExpression: string, subscriptionName: string) {
method unsubscribes (line 36) | unsubscribes (clientExpression: string, subscriptionName: string) {
FILE: test-e2e/framework-v3/listening.ts
type ListenType (line 6) | type ListenType = 'record' | 'event'
method doesNotRecieveMatch (line 9) | doesNotRecieveMatch (client: string, type: ListenType, match: boolean, p...
method recievesMatch (line 14) | recievesMatch (client: string, count: number, type: ListenType, subscrip...
method receivedUnMatch (line 19) | receivedUnMatch (client: string, count: number, type: ListenType, subscr...
method setupListenResponse (line 28) | setupListenResponse (client: string, accepts: boolean, type: ListenType,...
method listens (line 34) | listens (client: string, type: ListenType, pattern: string) {
method unlistens (line 54) | unlistens (client: string, type: ListenType, pattern: string) {
FILE: test-e2e/framework-v3/presence.ts
method notifiedUserStateChanged (line 10) | notifiedUserStateChanged (notifeeExpression: string, not: boolean, notif...
method globalQueryResult (line 23) | globalQueryResult (clientExpression: string, error: null | string, users...
method queryResult (line 39) | queryResult (clientExpression: string, users: string[], online: boolean) {
method subscribe (line 54) | subscribe (clientExpression: string, user?: string) {
method unsubscribe (line 71) | unsubscribe (clientExpression: string, user?: string) {
method getAll (line 81) | getAll (clientExpression: string, users?: string[]) {
FILE: test-e2e/framework-v3/record.ts
function getRecordData (line 7) | function getRecordData (clientExpression: string, recordName: string) {
function getListData (line 11) | function getListData (clientExpression: string, listName: string) {
method deleted (line 16) | deleted (clientExpression: string, recordName: string, called: boolean) {
method discarded (line 28) | discarded (clientExpression: string, recordName: string, called: boolean) {
method receivedUpdate (line 39) | receivedUpdate (clientExpression: string, recordName: string, data: stri...
method receivedUpdateForPath (line 48) | receivedUpdateForPath (clientExpression: string, recordName: string, pat...
method receivedNoUpdate (line 57) | receivedNoUpdate (clientExpression: string, recordName: string) {
method receivedNoUpdateForPath (line 63) | receivedNoUpdateForPath (clientExpression: string, recordName: string, p...
method receivedRecordError (line 69) | receivedRecordError (clientExpression: string, error: string, recordName...
method hasData (line 78) | hasData (clientExpression: string, recordName: string, data: string) {
method hasProviders (line 85) | hasProviders (clientExpression: string, recordName: string, without: boo...
method hasDataAtPath (line 91) | hasDataAtPath (clientExpression: string, recordName: string, path: strin...
method writeAckSuccess (line 98) | writeAckSuccess (clientExpression: string, recordName: string) {
method writeAckError (line 113) | writeAckError (clientExpression: string, recordName: string, errorMessag...
method snapshotSuccess (line 130) | snapshotSuccess (clientExpression: string, recordName: string, data: str...
method snapshotError (line 138) | snapshotError (clientExpression: string, recordName: string, data: strin...
method headSuccess (line 148) | headSuccess (clientExpression: string, recordName: string, data: number) {
method headError (line 156) | headError (clientExpression: string, recordName: string, data: string) {
method has (line 164) | has (clientExpression: string, recordName: string, expected: boolean) {
method hasEntries (line 172) | hasEntries (clientExpression: string, listName: string, data: string) {
method addedNotified (line 179) | addedNotified (clientExpression: string, listName: string, entryName: st...
method removedNotified (line 185) | removedNotified (clientExpression: string, listName: string, entryName: ...
method movedNotified (line 191) | movedNotified (clientExpression: string, listName: string, entryName: st...
method listChanged (line 197) | listChanged (clientExpression: string, listName: string, data: string) {
method anonymousRecordContains (line 205) | anonymousRecordContains (clientExpression: string, data: string) {
method getRecord (line 216) | getRecord (clientExpression: string, recordName: string) {
method subscribe (line 237) | subscribe (clientExpression: string, recordName: string, immediate: bool...
method unsubscribe (line 243) | unsubscribe (clientExpression: string, recordName: string) {
method subscribeWithPath (line 249) | subscribeWithPath (clientExpression: string, recordName: string, path: s...
method unsubscribeFromPath (line 256) | unsubscribeFromPath (clientExpression: string, recordName: string, path:...
method discard (line 262) | discard (clientExpression: string, recordName: string) {
method delete (line 268) | delete (clientExpression: string, recordName: string) {
method setupWriteAck (line 274) | setupWriteAck (clientExpression: string, recordName: string) {
method set (line 280) | set (clientExpression: string, recordName: string, data: string) {
method setWithPath (line 290) | setWithPath (clientExpression: string, recordName: string, path: string,...
method erase (line 300) | erase (clientExpression: string, recordName: string, path: string) {
method setData (line 310) | setData (clientExpression: string, recordName: string, data: string) {
method setDataWithWriteAck (line 316) | setDataWithWriteAck (clientExpression: string, recordName: string, data:...
method setDataWithPath (line 326) | setDataWithPath (clientExpression: string, recordName: string, path: str...
method snapshot (line 332) | snapshot (clientExpression: string, recordName: string) {
method has (line 338) | has (clientExpression: string, recordName: string) {
method head (line 344) | head (clientExpression: string, recordName: string) {
method getList (line 354) | getList (clientExpression: string, listName: string) {
method setEntries (line 376) | setEntries (clientExpression: string, listName: string, data: string) {
method addEntry (line 383) | addEntry (clientExpression: string, listName: string, entryName: string) {
method removeEntry (line 389) | removeEntry (clientExpression: string, listName: string, entryName: stri...
method getAnonymousRecord (line 399) | getAnonymousRecord (clientExpression: string) {
method setName (line 405) | setName (clientExpression: string, recordName: string) {
FILE: test-e2e/framework-v3/rpc.ts
method recievesResponse (line 65) | recievesResponse (clientExpression: string, rpc: string, data: string) {
method recievesResponseWithError (line 73) | recievesResponseWithError (clientExpression: string, eventually: boolean...
method providerCalled (line 84) | providerCalled (clientExpression: string, rpc: string, timesCalled: numb...
method provide (line 98) | provide (clientExpression: string, rpc: string) {
method unprovide (line 105) | unprovide (clientExpression: string, rpc: string) {
method make (line 111) | make (clientExpression: string, rpc: string, data: string) {
FILE: test-e2e/framework-v3/world.ts
method endTest (line 6) | endTest (done: (...args: any[]) => void) {
FILE: test-e2e/framework/client-handler.ts
type E2EClient (line 5) | interface E2EClient {
function createClient (line 13) | function createClient (clientName: string, server: string, options?: any) {
function getClientNames (line 133) | function getClientNames (expression: string) {
function getClients (line 147) | function getClients (expression: string) {
function assertNoErrors (line 151) | function assertNoErrors (client: string) {
FILE: test-e2e/framework/client.ts
method logsOut (line 7) | logsOut (clientExpression: string, done: Function) {
method connect (line 15) | connect (clientExpression: string, server: string) {
method connectAndLogin (line 21) | connectAndLogin (clientExpression: string, server: string, done: Functio...
method login (line 32) | login (clientExpression: string, username: string, password: string, don...
method attemptLogin (line 45) | attemptLogin (clientExpression: string, username: string, password: stri...
method receivedTooManyLoginAttempts (line 54) | receivedTooManyLoginAttempts (clientExpression: string) {
method recievesNoLoginResponse (line 62) | recievesNoLoginResponse (clientExpression: string) {
method recievesLoginResponse (line 68) | recievesLoginResponse (clientExpression: string, loginFailed: boolean, d...
method connectionTimesOut (line 86) | connectionTimesOut (clientExpression: string, done: Function) {
method receivedErrorOnce (line 97) | receivedErrorOnce (clientExpression: string, topicName: string, eventNam...
method receivedOneError (line 107) | receivedOneError (clientExpression: string, topicName: string, eventName...
method callbackCalled (line 118) | callbackCalled (clientExpression: string, eventName: string, notCalled: ...
method receivedNoErrors (line 138) | receivedNoErrors (clientExpression: string) {
method hadConnectionState (line 144) | hadConnectionState (clientExpression: string, had: boolean, state: boole...
FILE: test-e2e/framework/event.ts
method received (line 6) | received (clientExpression: string, doesReceive: boolean, subscriptionNa...
method publishes (line 23) | publishes (clientExpression: string, subscriptionName: string, data: str...
method subscribes (line 29) | subscribes (clientExpression: string, subscriptionName: string) {
method unsubscribes (line 36) | unsubscribes (clientExpression: string, subscriptionName: string) {
FILE: test-e2e/framework/listening.ts
type ListenType (line 7) | type ListenType = 'record' | 'event'
method doesNotRecieveMatch (line 10) | doesNotRecieveMatch (client: string, type: ListenType, match: boolean, p...
method recievesMatch (line 15) | recievesMatch (client: string, count: number, type: ListenType, subscrip...
method receivedUnMatch (line 20) | receivedUnMatch (client: string, count: number, type: ListenType, subscr...
method setupListenResponse (line 29) | setupListenResponse (client: string, accepts: boolean, type: ListenType,...
method listens (line 35) | listens (client: string, type: ListenType, pattern: string) {
method unlistens (line 52) | unlistens (client: string, type: ListenType, pattern: string) {
FILE: test-e2e/framework/presence.ts
method notifiedUserStateChanged (line 9) | notifiedUserStateChanged (notifeeExpression: string, not: boolean, notif...
method globalQueryResult (line 22) | globalQueryResult (clientExpression: string, error: null | string, users...
method queryResult (line 34) | queryResult (clientExpression: string, users: string[], online: boolean) {
method subscribe (line 49) | subscribe (clientExpression: string, user?: string) {
method unsubscribe (line 62) | unsubscribe (clientExpression: string, user?: string) {
method getAll (line 72) | getAll (clientExpression: string, users?: string[]) {
FILE: test-e2e/framework/record.ts
function getRecordData (line 6) | function getRecordData (clientExpression: string, recordName: string) {
function getListData (line 10) | function getListData (clientExpression: string, listName: string) {
method deleted (line 15) | deleted (clientExpression: string, recordName: string, called: boolean) {
method discarded (line 27) | discarded (clientExpression: string, recordName: string, called: boolean) {
method receivedUpdate (line 38) | receivedUpdate (clientExpression: string, recordName: string, data: stri...
method receivedUpdateForPath (line 47) | receivedUpdateForPath (clientExpression: string, recordName: string, pat...
method receivedNoUpdate (line 56) | receivedNoUpdate (clientExpression: string, recordName: string) {
method receivedNoUpdateForPath (line 62) | receivedNoUpdateForPath (clientExpression: string, recordName: string, p...
method receivedRecordError (line 68) | receivedRecordError (clientExpression: string, error: string, recordName...
method hasData (line 75) | hasData (clientExpression: string, recordName: string, data: string) {
method hasProviders (line 82) | hasProviders (clientExpression: string, recordName: string, without: boo...
method hasDataAtPath (line 88) | hasDataAtPath (clientExpression: string, recordName: string, path: strin...
method writeAckSuccess (line 95) | writeAckSuccess (clientExpression: string, recordName: string) {
method writeAckError (line 110) | writeAckError (clientExpression: string, recordName: string, errorMessag...
method snapshotSuccess (line 125) | snapshotSuccess (clientExpression: string, recordName: string, data: str...
method snapshotError (line 133) | snapshotError (clientExpression: string, recordName: string, data: strin...
method headSuccess (line 141) | headSuccess (clientExpression: string, recordName: string, data: number) {
method headError (line 149) | headError (clientExpression: string, recordName: string, data: string) {
method has (line 157) | has (clientExpression: string, recordName: string, expected: boolean) {
method hasEntries (line 165) | hasEntries (clientExpression: string, listName: string, data: string) {
method addedNotified (line 172) | addedNotified (clientExpression: string, listName: string, entryName: st...
method removedNotified (line 178) | removedNotified (clientExpression: string, listName: string, entryName: ...
method movedNotified (line 184) | movedNotified (clientExpression: string, listName: string, entryName: st...
method listChanged (line 190) | listChanged (clientExpression: string, listName: string, data: string) {
method anonymousRecordContains (line 198) | anonymousRecordContains (clientExpression: string, data: string) {
method getRecord (line 209) | getRecord (clientExpression: string, recordName: string) {
method subscribe (line 230) | subscribe (clientExpression: string, recordName: string, immediate: bool...
method unsubscribe (line 236) | unsubscribe (clientExpression: string, recordName: string) {
method subscribeWithPath (line 242) | subscribeWithPath (clientExpression: string, recordName: string, path: s...
method unsubscribeFromPath (line 249) | unsubscribeFromPath (clientExpression: string, recordName: string, path:...
method discard (line 255) | discard (clientExpression: string, recordName: string) {
method delete (line 261) | delete (clientExpression: string, recordName: string) {
method setupWriteAck (line 267) | setupWriteAck (clientExpression: string, recordName: string) {
method set (line 273) | set (clientExpression: string, recordName: string, data: string) {
method setWithPath (line 283) | setWithPath (clientExpression: string, recordName: string, path: string,...
method erase (line 293) | erase (clientExpression: string, recordName: string, path: string) {
method setData (line 303) | setData (clientExpression: string, recordName: string, data: string) {
method setDataWithWriteAck (line 309) | setDataWithWriteAck (clientExpression: string, recordName: string, data:...
method setDataWithPath (line 319) | setDataWithPath (clientExpression: string, recordName: string, path: str...
method snapshot (line 325) | snapshot (clientExpression: string, recordName: string) {
method has (line 331) | has (clientExpression: string, recordName: string) {
method head (line 337) | head (clientExpression: string, recordName: string) {
method getList (line 347) | getList (clientExpression: string, listName: string) {
method setEntries (line 369) | setEntries (clientExpression: string, listName: string, data: string) {
method addEntry (line 376) | addEntry (clientExpression: string, listName: string, entryName: string) {
method removeEntry (line 382) | removeEntry (clientExpression: string, listName: string, entryName: stri...
method getAnonymousRecord (line 392) | getAnonymousRecord (clientExpression: string) {
method setName (line 398) | setName (clientExpression: string, recordName: string) {
FILE: test-e2e/framework/rpc.ts
method recievesResponse (line 65) | recievesResponse (clientExpression: string, rpc: string, data: string) {
method recievesResponseWithError (line 73) | recievesResponseWithError (clientExpression: string, eventually: boolean...
method providerCalled (line 84) | providerCalled (clientExpression: string, rpc: string, timesCalled: numb...
method provide (line 98) | provide (clientExpression: string, rpc: string) {
method unprovide (line 105) | unprovide (clientExpression: string, rpc: string) {
method make (line 111) | make (clientExpression: string, rpc: string, data: string) {
FILE: test-e2e/framework/world.ts
method endTest (line 6) | endTest (done: (...args: any[]) => void) {
FILE: test-e2e/tools/e2e-authentication.ts
type AuthData (line 4) | interface AuthData {
class E2EAuthentication (line 10) | class E2EAuthentication extends DeepstreamPlugin implements DeepstreamAu...
method isValidUser (line 20) | public async isValidUser (headers: JSONObject, authData: AuthData) {
FILE: test-e2e/tools/e2e-cluster-node.ts
class E2EClusterNode (line 5) | class E2EClusterNode extends DeepstreamPlugin implements DeepstreamClust...
method constructor (line 9) | constructor (options: any, services: DeepstreamServices, private confi...
method sendDirect (line 14) | public sendDirect (toServer: string, message: Message, metaData?: any)...
method send (line 21) | public send (message: Message, metaData?: any): void {
method subscribe (line 32) | public subscribe<SpecificMessage> (topic: STATE_REGISTRY_TOPIC, callba...
method close (line 41) | public async close () {
FILE: test-e2e/tools/e2e-harness.ts
constant SERVER_STOP_OR_START_DURATION (line 16) | const SERVER_STOP_OR_START_DURATION = 200
class E2EHarness (line 20) | class E2EHarness extends EventEmitter {
method constructor (line 23) | constructor (private ports: number[], private enableLogging: boolean =...
method getServerName (line 28) | public getServerName (serverId: number) {
method getUrl (line 32) | public getUrl (serverId: number) {
method getHttpUrl (line 36) | public getHttpUrl (serverId: number) {
method getAuthUrl (line 40) | public getAuthUrl (serverId: number) {
method updateStorageDirectly (line 44) | public async updateStorageDirectly (recordName: string, version: numbe...
method deleteFromStorageDirectly (line 52) | public async deleteFromStorageDirectly (recordName: string) {
method start (line 60) | public async start () {
method stop (line 67) | public async stop () {
method updatePermissions (line 72) | public async updatePermissions (type: string) {
method stopServer (line 80) | public stopServer (serverId: number) {
method startServer (line 101) | public async startServer (serverId: number) {
method whenReady (line 123) | public async whenReady () {
method whenStopped (line 134) | public async whenStopped () {
FILE: test-e2e/tools/e2e-logger.ts
type Log (line 3) | interface Log {
class E2ELogger (line 9) | class E2ELogger extends DeepstreamPlugin implements DeepstreamLogger {
method setLogLevel (line 14) | public setLogLevel (logLevel: LOG_LEVEL): void {
method shouldLog (line 18) | public shouldLog () {
method error (line 22) | public error (event: EVENT, logMessage: string) {
method warn (line 26) | public warn (event: EVENT, logMessage: string) {
method info (line 30) | public info (event: EVENT, logMessage: string) {
method debug (line 34) | public debug (event: EVENT, logMessage: string) {
method fatal (line 38) | public fatal (event: EVENT, logMessage: string) {
method getNameSpace (line 42) | public getNameSpace (namespace: string): NamespacedLogger {
method log (line 53) | private log (logLevel: LOG_LEVEL, event: EVENT, logMessage: string) {
FILE: types/global.d.ts
type Global (line 2) | interface Global {
FILE: types/uws.d.ts
type us_listen_socket (line 18) | interface us_listen_socket {
type us_socket (line 25) | interface us_socket {
type us_socket_context_t (line 31) | interface us_socket_context_t {
type RecognizedString (line 45) | type RecognizedString = string | ArrayBuffer | Uint8Array | Int8Array | ...
type WebSocket (line 50) | interface WebSocket<UserData> {
type HttpResponse (line 112) | interface HttpResponse {
type HttpRequest (line 206) | interface HttpRequest {
type WebSocketBehavior (line 228) | interface WebSocketBehavior<UserData> {
type AppOptions (line 268) | interface AppOptions {
type ListenOptions (line 279) | enum ListenOptions {
type TemplatedApp (line 285) | interface TemplatedApp {
type MultipartField (line 344) | interface MultipartField {
type CompressOptions (line 355) | type CompressOptions = number;
Condensed preview — 254 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,105K chars).
[
{
"path": ".dockerignore",
"chars": 99,
"preview": "**/.git/\n**/.github/\n**/node_modules/\n\n**/Dockerfile\n**/Dockerfile.*\n\n**/.env.*.local\n**/.env.local"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 889,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
},
{
"path": ".github/workflows/lint-test.yml",
"chars": 547,
"preview": "name: lint-and-test\n\non: [push, pull_request]\n\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/c"
},
{
"path": ".github/workflows/release.yml",
"chars": 5521,
"preview": "name: release\n\non:\n push:\n # Sequence of patterns matched against refs/tags\n tags:\n - 'v*' # Push events to "
},
{
"path": ".gitignore",
"chars": 819,
"preview": "heap-snapshots\n.nyc_combined_coverage\ndist\n.DS_Store\n.vscode/settings.json\n.nyc_output\ntemp-e2e-test\nlocal-storage\n\n# Lo"
},
{
"path": ".gitmodules",
"chars": 1695,
"preview": "[submodule \"test-e2e/features\"]\n\tpath = test-e2e/features\n\turl = https://github.com/deepstreamIO/deepstream.io-e2e.git\n["
},
{
"path": ".npmignore",
"chars": 504,
"preview": "# Typescript files\n/scripts\n/bin\n.tsconfig.json\n.tslint.json\n\n# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Dir"
},
{
"path": "CHANGELOG.md",
"chars": 37664,
"preview": "## [10.0.0] - 2025.08.02\n\n### Fix - BREAKING CHANGE\n\nThe storage authentication service, when creating new users automat"
},
{
"path": "Dockerfile",
"chars": 711,
"preview": "FROM node:22 as builder\nWORKDIR /app\n\nCOPY package*.json ./\n\nRUN npm ci\nRUN npm install --omit=dev \\\n @deepstream/cac"
},
{
"path": "Dockerfile.alpine",
"chars": 899,
"preview": "FROM node:22-alpine as builder\nWORKDIR /app\n# RUN curl \"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip\" -o \"aw"
},
{
"path": "LICENSE",
"chars": 1057,
"preview": "Copyright 2019 deepstreamHub GmbH\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this "
},
{
"path": "README.md",
"chars": 4067,
"preview": "# deepstream - the open realtime server <a href='https://deepstreamio.github.io/'><img src='./elton-square.png' height='"
},
{
"path": "SECURITY.md",
"chars": 325,
"preview": "# Security Policy\n\n## Reporting a Vulnerability\n\nReport the vulnerability in the security [advisory section](https://git"
},
{
"path": "ascii-logo.txt",
"chars": 283,
"preview": " _ _ \n __| | ___ ___ _ __ ___| |_ _ __ ___ __ _ _ __ ____ \n / _` |/ _ \\/ _ \\ '_ \\/ __| __"
},
{
"path": "bin/deepstream-cluster.ts",
"chars": 2938,
"preview": "import { Command } from 'commander'\nimport * as cluster from 'cluster'\nconst numCPUs = require('os').cpus().length\nimpor"
},
{
"path": "bin/deepstream-daemon.ts",
"chars": 911,
"preview": "// @ts-ignore\nimport * as dsDaemon from '../src/service/daemon'\nimport { Command } from 'commander'\n\nexport const daemon"
},
{
"path": "bin/deepstream-hash.ts",
"chars": 1542,
"preview": "import * as jsYamlLoader from '../src/config/js-yaml-loader'\nimport { Command } from 'commander'\nimport { createHash } f"
},
{
"path": "bin/deepstream-info.ts",
"chars": 987,
"preview": "import * as jsYamlLoader from '../src/config/js-yaml-loader'\nimport { Command } from 'commander'\nimport { getDSInfo } fr"
},
{
"path": "bin/deepstream-nginx.ts",
"chars": 3058,
"preview": "// @ts-ignore\nimport * as dsService from '../src/service/service'\nimport { Command } from 'commander'\nimport { writeFile"
},
{
"path": "bin/deepstream-service.ts",
"chars": 2049,
"preview": "// @ts-ignore\nimport * as dsService from '../src/service/service'\nimport { Command } from 'commander'\n\nexport const serv"
},
{
"path": "bin/deepstream-start.ts",
"chars": 3020,
"preview": "import { Command } from 'commander'\nimport { EVENT } from '@deepstream/types'\n\nexport const start = (program: Command) ="
},
{
"path": "bin/deepstream.ts",
"chars": 665,
"preview": "#!/usr/bin/env node\nimport * as pgk from '../package.json'\n\nimport { Command } from 'commander'\nimport { start } from '."
},
{
"path": "conf/config.yml",
"chars": 12573,
"preview": "# General\n# Each server within a cluster needs a unique name. Set to UUID to have deepstream autogenerate a unique id\nse"
},
{
"path": "conf/permissions.yml",
"chars": 264,
"preview": "presence:\n \"*\":\n allow: true\nrecord:\n \"*\":\n create: true\n write: true\n read: true\n delete: true\n lis"
},
{
"path": "conf/users.yml",
"chars": 415,
"preview": "# Username\nuserA:\n # Password hash ( hash options passed within config.yml )\n # This hash represents clear text \"passw"
},
{
"path": "package.json",
"chars": 4905,
"preview": "{\n \"name\": \"@deepstream/server\",\n \"version\": \"10.0.0\",\n \"description\": \"a scalable server for realtime webapps\",\n \"m"
},
{
"path": "scripts/connector/package-connector.sh",
"chars": 1827,
"preview": "#!/bin/bash\nPACKAGED_NODE_VERSION=\"v10\"\nOS=$( node -e \"console.log(require('os').platform())\" )\nNODE_VERSION=$( node --v"
},
{
"path": "scripts/connector/test-connector.sh",
"chars": 2480,
"preview": "#!/bin/bash\nset -e\n\ncurl -o deepstream_package.json https://raw.githubusercontent.com/deepstreamIO/deepstream.io/master/"
},
{
"path": "scripts/details.js",
"chars": 1015,
"preview": "var exec = require( 'child_process' ).execSync;\nvar fs = require( 'fs' );\nvar path = require( 'path' );\nvar pkg = requir"
},
{
"path": "scripts/executable-test.js",
"chars": 309,
"preview": "const { exec } = require('child_process')\n\nexec('./build/deepstream info', (error, stdout, stderr) => {\n if (error) {"
},
{
"path": "scripts/license-aggregator.js",
"chars": 7086,
"preview": "#!/usr/bin/env node\nconst path = require('path')\nconst fs = require('fs')\nconst child_process = require('child_process')"
},
{
"path": "scripts/linux-package.sh",
"chars": 3551,
"preview": "#!/bin/bash\nset -e\n\nif [[ -z $1 ]]; then echo \"First param is distro ( centos | debian | ubuntu | ... )\"; exit 1; fi\nif "
},
{
"path": "scripts/linux-test.sh",
"chars": 1893,
"preview": "#!/bin/bash\nset -e\n\nif [ -z $1 ]; then echo \"First param is distro ( centos | debian | ubuntu | ... )\"; exit 1; fi\nif [ "
},
{
"path": "scripts/node-test.js",
"chars": 192,
"preview": "const { Deepstream } = require('../dist/src/deepstream.io')\n\nconst server = new Deepstream({})\nserver.start()\nserver.on("
},
{
"path": "scripts/package.sh",
"chars": 9356,
"preview": "#!/bin/bash\nset -e\n\nLTS_VERSION=\"22\"\nNODE_VERSION=$( node --version )\nNODE_VERSION_WITHOUT_V=$( echo ${NODE_VERSION} | c"
},
{
"path": "scripts/pkg.js",
"chars": 445,
"preview": "const { exec } = require('@yao-pkg/pkg')\n\nconst LTS = process.env.LTS\nlet OS = process.env.OS\n\nif (OS === 'win32') {\n O"
},
{
"path": "scripts/release.sh",
"chars": 456,
"preview": "if [ -z $1 ]; then\n\techo \"Please provide a release version: patch, minor or major\"\n\texit\nfi\n\nif [ $( npm whoami ) != \"de"
},
{
"path": "scripts/resources/PackageInfo",
"chars": 57,
"preview": "<?xml version=\"1.0\"?>\n<pkg-info auth=\"none\">\n</pkg-info>\n"
},
{
"path": "scripts/resources/daemon/after-install",
"chars": 261,
"preview": "cp /etc/deepstream/conf.d/* /etc/deepstream/\n\nmkdir -p /var/run/deepstream\nmkdir -p /var/log/deepstream\nmkdir -p /var/li"
},
{
"path": "scripts/resources/daemon/after-upgrade",
"chars": 0,
"preview": ""
},
{
"path": "scripts/resources/daemon/before-remove",
"chars": 15,
"preview": "deepstream stop"
},
{
"path": "scripts/resources/daemon/before-upgrade",
"chars": 90,
"preview": "cd /var/lib/deepstream\nrm -rf deepstream.io-logger-winston*\nrm -rf /etc/deepstream/conf.d\n"
},
{
"path": "scripts/resources/missing-licenses.txt",
"chars": 1488,
"preview": "----------------------------------------------------------------------------\n\nMISSING LICENSES\n\n------------------------"
},
{
"path": "scripts/resources/node.rc",
"chars": 1161,
"preview": "#include \"winresrc.h\"\n#include \"node_version.h\"\n\n// Application icon\n1 ICON deepstream.ico\n\n// Version resource\nVS_VERSI"
},
{
"path": "scripts/sanity-test.sh",
"chars": 1207,
"preview": "#!/bin/bash\nset -e\n\nif [[ $1 == \"deb\" ]]; then\n source /etc/lsb-release && echo \"deb http://dl.bintray.com/deepstreamio"
},
{
"path": "scripts/setup.sh",
"chars": 201,
"preview": "git clone https://github.com/deepstreamIO/deepstream.io.git\ncd deepstream.io\nsed -i 's/git@github.com:/https:\\/\\/github."
},
{
"path": "scripts/trigger-build.sh",
"chars": 434,
"preview": "if [ -z $1 ]; then\n echo \"Missing branch name as first arguments\"\n exit 1\nfi\n\nbody=\"{\n \\\"request\\\": {\n \\\"branch\\\":\\\""
},
{
"path": "scripts/tsc.sh",
"chars": 320,
"preview": "#!/usr/bin/env bash\nrm -rf dist\n./node_modules/.bin/tsc\ncp ./ascii-logo.txt ./dist/ascii-logo.txt\ncp ./package.json ./di"
},
{
"path": "src/config/config-initialiser.spec.ts",
"chars": 7548,
"preview": "import { expect } from 'chai'\n\nimport * as path from 'path'\nimport * as defaultConfig from '../default-options'\nimport *"
},
{
"path": "src/config/config-initialiser.ts",
"chars": 22107,
"preview": "import { readFileSync } from 'fs'\nimport { join } from 'path'\nimport { EOL } from 'os'\n\nimport * as utils from '../utils"
},
{
"path": "src/config/config-validator.ts",
"chars": 7611,
"preview": "import {Ajv} from 'ajv'\nimport addFormat from 'ajv-formats'\nimport betterAjvErrors from 'better-ajv-errors'\n\nimport { LO"
},
{
"path": "src/config/ds-info.ts",
"chars": 1061,
"preview": "import * as fs from 'fs'\nimport * as path from 'path'\nimport * as os from 'os'\nimport * as glob from 'glob'\n\nexport cons"
},
{
"path": "src/config/file-utils.spec.ts",
"chars": 2454,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as fileUtils from './file-utils'\nconst path = require('path')\n\nde"
},
{
"path": "src/config/file-utils.ts",
"chars": 2354,
"preview": "import * as fs from 'fs'\nimport * as path from 'path'\n\n/**\n* Append the global library directory as the prefix to any pa"
},
{
"path": "src/config/js-yaml-loader.spec.ts",
"chars": 18656,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport { spy } from 'sinon'\n\nimport * as path from 'path'\nconst proxyquire "
},
{
"path": "src/config/js-yaml-loader.ts",
"chars": 8463,
"preview": "import * as fs from 'fs'\nimport * as yaml from 'js-yaml'\nimport * as path from 'path'\n\nimport { get as getDefaultOptions"
},
{
"path": "src/connection-endpoint/base/connection-endpoint.spec.ts",
"chars": 24026,
"preview": "// import * as C from '../../src/constants'\n// const proxyquire = require('proxyquire').noPreserveCache()\n// import uwsM"
},
{
"path": "src/connection-endpoint/base/connection-endpoint.ts",
"chars": 14414,
"preview": "\nimport { Message, ParseResult, PARSER_ACTION, TOPIC, CONNECTION_ACTION, ALL_ACTIONS, JSONObject, AUTH_ACTION } from '.."
},
{
"path": "src/connection-endpoint/base/socket-wrapper.ts",
"chars": 4517,
"preview": "import { TOPIC, CONNECTION_ACTION, ParseResult, Message } from '../../constants'\nimport { WebSocketServerConfig } from '"
},
{
"path": "src/connection-endpoint/http/connection-endpoint.spec.ts",
"chars": 5343,
"preview": "import { expect } from 'chai'\nimport * as needle from 'needle'\n\nimport LoggerMock from '../../test/mock/logger-mock'\nimp"
},
{
"path": "src/connection-endpoint/http/connection-endpoint.ts",
"chars": 16146,
"preview": "import JIFHandler from '../../jif/jif-handler'\nimport HTTPSocketWrapper from './socket-wrapper'\nimport * as HTTPStatus f"
},
{
"path": "src/connection-endpoint/http/socket-wrapper.ts",
"chars": 3473,
"preview": "import { parseData } from '@deepstream/protobuf/dist/src/message-parser'\nimport { EventEmitter } from 'events'\nimport { "
},
{
"path": "src/connection-endpoint/mqtt/connection-endpoint.ts",
"chars": 5322,
"preview": "import { createMQTTSocketWrapper} from './socket-wrapper-factory'\nimport { DeepstreamServices, SocketWrapper, Deepstream"
},
{
"path": "src/connection-endpoint/mqtt/message-parser.ts",
"chars": 2028,
"preview": "import { TOPIC, EVENT_ACTION, Message, PARSER_ACTION, RECORD_ACTION } from '../../constants'\n\nexport const parseMQTT = ("
},
{
"path": "src/connection-endpoint/mqtt/socket-wrapper-factory.ts",
"chars": 5745,
"preview": "import { StatefulSocketWrapper, DeepstreamServices, UnauthenticatedSocketWrapper, EVENT, NamespacedLogger } from '@deeps"
},
{
"path": "src/connection-endpoint/websocket/binary/connection-endpoint.ts",
"chars": 770,
"preview": "import BaseWebsocketConnectionEndpoint, { WebSocketServerConfig } from '../../base/connection-endpoint'\nimport { createW"
},
{
"path": "src/connection-endpoint/websocket/binary/socket-wrapper-factory.ts",
"chars": 1667,
"preview": "import * as binaryMessageBuilder from '@deepstream/protobuf/dist/src/message-builder'\nimport * as binaryMessageParser fr"
},
{
"path": "src/connection-endpoint/websocket/json/connection-endpoint.ts",
"chars": 675,
"preview": "import WebsocketConnectionEndpoint, { WebSocketServerConfig } from '../../base/connection-endpoint'\nimport {createWSSock"
},
{
"path": "src/connection-endpoint/websocket/json/socket-wrapper-factory.ts",
"chars": 1439,
"preview": "import { ParseResult, Message } from '../../../constants'\nimport { WebSocketServerConfig } from '../../base/connection-e"
},
{
"path": "src/connection-endpoint/websocket/text/connection-endpoint.ts",
"chars": 1715,
"preview": "import { WebSocketServerConfig } from '../../base/connection-endpoint'\nimport BaseWebsocketConnectionEndpoint from '../."
},
{
"path": "src/connection-endpoint/websocket/text/socket-wrapper-factory.ts",
"chars": 1342,
"preview": "import { ParseResult, Message } from '../../../constants'\nimport * as textMessageBuilder from './text-protocol/message-b"
},
{
"path": "src/connection-endpoint/websocket/text/text-protocol/constants.ts",
"chars": 11081,
"preview": "import {\n AUTH_ACTION as AA,\n CONNECTION_ACTION as CA,\n EVENT_ACTION as EA,\n PARSER_ACTION as XA,\n PRESENCE_ACTION "
},
{
"path": "src/connection-endpoint/websocket/text/text-protocol/message-builder.ts",
"chars": 14298,
"preview": "import {\n ACTIONS_BYTE_TO_PAYLOAD as ABP,\n ACTIONS_BYTE_TO_TEXT as ABT,\n AUTH_ACTIONS as AA,\n CONNECTION_ACTIONS as "
},
{
"path": "src/connection-endpoint/websocket/text/text-protocol/message-parser.ts",
"chars": 9906,
"preview": "import {\n ACTIONS_BYTE_TO_PAYLOAD as ABP,\n ACTIONS_TEXT_TO_BYTE,\n AUTH_ACTIONS as AA,\n CONNECTION_ACTIONS as CA,\n D"
},
{
"path": "src/connection-endpoint/websocket/text/text-protocol/utils.ts",
"chars": 88,
"preview": "export const isWriteAck = (action: any) => false\n\nexport const WRITE_ACK_TO_ACTION = {}\n"
},
{
"path": "src/constants.ts",
"chars": 650,
"preview": "export * from '@deepstream/protobuf/dist/types/all'\nexport * from '@deepstream/protobuf/dist/types/messages'\n\nexport enu"
},
{
"path": "src/deepstream.io.spec.ts",
"chars": 620,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport { Deepstream } from './deepstream.io'\nimport { PromiseDelay } from "
},
{
"path": "src/deepstream.io.ts",
"chars": 17565,
"preview": "require('source-map-support').install()\n\nimport { EventEmitter } from 'events'\n\nimport * as pkg from '../package.json'\ni"
},
{
"path": "src/default-options.ts",
"chars": 3818,
"preview": "import { getUid } from './utils/utils'\nimport { DeepstreamConfig, LOG_LEVEL } from '@deepstream/types'\n\nconst WebSocketD"
},
{
"path": "src/handlers/event/event-handler.spec.ts",
"chars": 3908,
"preview": "import 'mocha'\n\nimport * as C from '../../constants'\nimport EventHandler from './event-handler'\n\nimport * as testHelper "
},
{
"path": "src/handlers/event/event-handler.ts",
"chars": 2832,
"preview": "import { EVENT_ACTION, TOPIC, EventMessage, ListenMessage, STATE_REGISTRY_TOPIC, BulkSubscriptionMessage } from '../../c"
},
{
"path": "src/handlers/monitoring/monitoring.ts",
"chars": 934,
"preview": "import { DeepstreamConfig, DeepstreamServices, SubscriptionRegistry, SocketWrapper, Handler } from '@deepstream/types'\ni"
},
{
"path": "src/handlers/presence/presence-handler.spec.ts",
"chars": 6528,
"preview": "import 'mocha'\n\nimport PresenceHandler from './presence-handler'\n\nconst EVERYONE = '%_EVERYONE_%'\n\nimport * as C from '."
},
{
"path": "src/handlers/presence/presence-handler.ts",
"chars": 6683,
"preview": "import { PARSER_ACTION, PRESENCE_ACTION, TOPIC, PresenceMessage, Message, BulkSubscriptionMessage, STATE_REGISTRY_TOPIC "
},
{
"path": "src/handlers/record/record-deletion.spec.ts",
"chars": 3529,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport {spy} from 'sinon'\n\nimport RecordDeletion from './record-deletion'\n\n"
},
{
"path": "src/handlers/record/record-deletion.ts",
"chars": 3865,
"preview": "import { DeepstreamConfig, DeepstreamServices, SocketWrapper } from '@deepstream/types'\nimport { Message, RecordMessage,"
},
{
"path": "src/handlers/record/record-handler-permission.spec.ts",
"chars": 3359,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as C from '../../../src/constants'\n\nimport RecordHandler from './"
},
{
"path": "src/handlers/record/record-handler.spec.ts",
"chars": 15535,
"preview": "import 'mocha'\n\nimport * as C from '../../../src/constants'\nimport { expect } from 'chai'\n\nimport RecordHandler from './"
},
{
"path": "src/handlers/record/record-handler.ts",
"chars": 25482,
"preview": "import RecordDeletion from './record-deletion'\nimport { recordRequestBinding } from './record-request'\nimport { RecordTr"
},
{
"path": "src/handlers/record/record-request.spec.ts",
"chars": 10973,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport {spy} from 'sinon'\n\nimport * as C from '../../constants'\nimport { re"
},
{
"path": "src/handlers/record/record-request.ts",
"chars": 5779,
"preview": "import { SocketWrapper, DeepstreamServices, DeepstreamConfig } from '@deepstream/types'\nimport { Message, RECORD_ACTION "
},
{
"path": "src/handlers/record/record-transition.spec.ts",
"chars": 14131,
"preview": "import 'mocha'\n\nimport * as M from './test-messages'\nimport * as C from '../../constants'\nimport { getTestMocks } from '"
},
{
"path": "src/handlers/record/record-transition.ts",
"chars": 15121,
"preview": "import { setValue as setPathValue } from '../../utils/json-path'\nimport RecordHandler from './record-handler'\nimport { r"
},
{
"path": "src/handlers/record/record-write-acknowledgement.spec.ts",
"chars": 3513,
"preview": "/*\n'use strict'\n\nconst M = require('./messages')\nimport * as C from '../../src/constants'\nimport { getTestMocks } from '"
},
{
"path": "src/handlers/record/test-messages.ts",
"chars": 3856,
"preview": "import * as C from '../../constants'\n\nexport const deletionMsg = {\n topic: C.TOPIC.RECORD,\n action: C.RECORD_ACTION.DE"
},
{
"path": "src/handlers/rpc/rpc-handler.spec.ts",
"chars": 14001,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as C from '../../constants'\nimport RpcHandler from './rpc-handler"
},
{
"path": "src/handlers/rpc/rpc-handler.ts",
"chars": 9084,
"preview": "import { PARSER_ACTION, RPC_ACTION, TOPIC, RPCMessage, BulkSubscriptionMessage, STATE_REGISTRY_TOPIC } from '../../const"
},
{
"path": "src/handlers/rpc/rpc-proxy.spec.ts",
"chars": 946,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as C from '../../constants'\nimport * as testHelper from '../../te"
},
{
"path": "src/handlers/rpc/rpc-proxy.ts",
"chars": 1812,
"preview": "import { RPC_ACTION, RPCMessage, ParseResult } from '../../constants'\nimport { SimpleSocketWrapper, DeepstreamConfig, De"
},
{
"path": "src/handlers/rpc/rpc.ts",
"chars": 5628,
"preview": "import { RPC_ACTION, TOPIC, RPCMessage, Message } from '../../constants'\nimport RpcHandler from './rpc-handler'\nimport {"
},
{
"path": "src/jif/jif-handler.spec.ts",
"chars": 17528,
"preview": "import { expect } from 'chai'\n\nconst JIFHandler = require('./jif-handler').default\nimport LoggerMock from '../test/mock/"
},
{
"path": "src/jif/jif-handler.ts",
"chars": 10956,
"preview": "import {\n EVENT_ACTION,\n PRESENCE_ACTION,\n RECORD_ACTION,\n RPC_ACTION,\n TOPIC,\n Message,\n ALL_ACTIONS,\n ACTIONS\n"
},
{
"path": "src/jif/jif-schema.ts",
"chars": 4806,
"preview": "export const jifSchema = {\n title: 'JSON Interchange Format',\n description: 'A JSON format for interaction with Deepst"
},
{
"path": "src/listen/listener-registry.spec.ts",
"chars": 17728,
"preview": "import 'mocha'\n\nimport * as C from '../constants'\nimport ListenerTestUtils from './listener-test-utils'\n\nimport 'mocha'\n"
},
{
"path": "src/listen/listener-registry.ts",
"chars": 19870,
"preview": "import { EVENT_ACTION, RECORD_ACTION, TOPIC, ListenMessage, STATE_REGISTRY_TOPIC } from '../constants'\nimport { EVENT, S"
},
{
"path": "src/listen/listener-test-utils.ts",
"chars": 9390,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport { ListenerRegistry } from './listener-registry'\nimport * as testHel"
},
{
"path": "src/plugins/heap-snapshot/heap-snapshot.ts",
"chars": 1783,
"preview": "import { DeepstreamPlugin, DeepstreamServices, EVENT } from '@deepstream/types'\nimport { writeHeapSnapshot } from 'v8'\ni"
},
{
"path": "src/service/daemon.ts",
"chars": 3170,
"preview": "// Handle input parameters\nimport { spawn, ChildProcess } from 'child_process'\n\nconst maxMilliseconds = 5000\n\nfunction _"
},
{
"path": "src/service/service.ts",
"chars": 6894,
"preview": "import { exec } from 'child_process'\n\nimport { existsSync, unlinkSync, chmodSync, writeFileSync } from 'fs'\n\nimport syst"
},
{
"path": "src/service/template/initd.ts",
"chars": 2190,
"preview": "export default (d: any) =>\n`#!/bin/bash\n\n### BEGIN INIT INFO\n# Provides: ${d.name}\n# Required-Start:\n# Required-Sto"
},
{
"path": "src/service/template/systemd.ts",
"chars": 295,
"preview": "export default (d: any) =>\n`[Unit]\nDescription=${d.name}\nAfter=network.target\n\n[Service]\nType=simple\nStandardOutput=${d."
},
{
"path": "src/services/authentication/combine/combine-authentication.ts",
"chars": 1522,
"preview": "import { DeepstreamPlugin, DeepstreamAuthenticationCombiner, DeepstreamAuthentication, UserAuthenticationCallback } from"
},
{
"path": "src/services/authentication/file/file-based-authentication.spec.ts",
"chars": 8355,
"preview": "import { spy, assert } from 'sinon'\nimport { expect } from 'chai'\nimport { FileBasedAuthentication } from './file-based-"
},
{
"path": "src/services/authentication/file/file-based-authentication.ts",
"chars": 4090,
"preview": "import { DeepstreamPlugin, DeepstreamAuthentication, DeepstreamServices, EVENT } from '@deepstream/types'\nimport { valid"
},
{
"path": "src/services/authentication/http/http-authentication.spec.ts",
"chars": 7761,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport TestHttpServer from '../../../test/helper/test-http-server'\nimport M"
},
{
"path": "src/services/authentication/http/http-authentication.ts",
"chars": 6098,
"preview": "import { post } from 'needle'\nimport { EVENT, DeepstreamPlugin, DeepstreamServices, DeepstreamConfig, DeepstreamAuthenti"
},
{
"path": "src/services/authentication/open/open-authentication.spec.ts",
"chars": 910,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport { spy } from 'sinon'\n\nimport { OpenAuthentication } from './open-aut"
},
{
"path": "src/services/authentication/open/open-authentication.ts",
"chars": 838,
"preview": "import { DeepstreamPlugin, DeepstreamAuthentication } from '@deepstream/types'\nimport { JSONObject } from '../../../cons"
},
{
"path": "src/services/authentication/storage/storage-based-authentication.ts",
"chars": 4592,
"preview": "import { DeepstreamPlugin, DeepstreamAuthentication, DeepstreamServices, EVENT, DeepstreamAuthenticationResult } from '@"
},
{
"path": "src/services/cache/local-cache.spec.ts",
"chars": 1586,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport {spy} from 'sinon'\nimport { LocalCache } from './local-cache'\n\ndescr"
},
{
"path": "src/services/cache/local-cache.ts",
"chars": 1746,
"preview": "import { DeepstreamPlugin, DeepstreamCache, StorageWriteCallback, StorageReadCallback, StorageHeadBulkCallback, StorageH"
},
{
"path": "src/services/cluster-node/single-cluster-node.ts",
"chars": 510,
"preview": "import { TOPIC, Message } from '../../constants'\nimport { DeepstreamClusterNode, DeepstreamPlugin } from '@deepstream/ty"
},
{
"path": "src/services/cluster-node/vertical-cluster-node.ts",
"chars": 3007,
"preview": "import { Message, TOPIC } from '../../constants'\nimport * as cluster from 'cluster'\nimport { EventEmitter } from 'events"
},
{
"path": "src/services/cluster-registry/distributed-cluster-registry.ts",
"chars": 7022,
"preview": "import { DeepstreamServices, DeepstreamConfig, ClusterRegistry, DeepstreamPlugin, EVENT } from '@deepstream/types'\nimpor"
},
{
"path": "src/services/cluster-registry/distributed-state-registry-factory.ts",
"chars": 1145,
"preview": "import { DeepstreamPlugin, DeepstreamServices, DeepstreamConfig, StateRegistryFactory, StateRegistry } from '@deepstream"
},
{
"path": "src/services/cluster-state/distributed-state-registry-factory.ts",
"chars": 1130,
"preview": "import { DeepstreamPlugin, DeepstreamServices, DeepstreamConfig, StateRegistryFactory, StateRegistry } from '@deepstream"
},
{
"path": "src/services/cluster-state/distributed-state-registry.ts",
"chars": 12596,
"preview": "import { TOPIC, STATE_ACTION, StateMessage } from '../../constants'\nimport { DeepstreamServices, StateRegistry, StateReg"
},
{
"path": "src/services/cluster-state/single-state-registry.ts",
"chars": 2005,
"preview": "import { StateRegistry, DeepstreamPlugin, StateRegistryCallback } from '@deepstream/types'\nimport { EventEmitter } from "
},
{
"path": "src/services/http/node/node-http.ts",
"chars": 14011,
"preview": "import { DeepstreamPlugin, DeepstreamHTTPService, EVENT, PostRequestHandler, GetRequestHandler, DeepstreamHTTPMeta, Deep"
},
{
"path": "src/services/http/uws/uws-http.ts",
"chars": 17969,
"preview": "import { DeepstreamPlugin, DeepstreamHTTPService, PostRequestHandler, GetRequestHandler, DeepstreamServices, DeepstreamC"
},
{
"path": "src/services/lock/distributed-lock-registry.ts",
"chars": 6240,
"preview": "import {EventEmitter} from 'events'\nimport Timeout = NodeJS.Timeout\nimport { DeepstreamPlugin, DeepstreamLockRegistry, D"
},
{
"path": "src/services/logger/pino/pino-logger.ts",
"chars": 3970,
"preview": "import pino, { LoggerOptions } from 'pino'\nimport { LOG_LEVEL, DeepstreamPlugin, DeepstreamLogger, DeepstreamConfig, Dee"
},
{
"path": "src/services/logger/std/std-out-logger.spec.ts",
"chars": 1612,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport {spy} from 'sinon'\n\nimport { StdOutLogger } from './std-out-logger'\n"
},
{
"path": "src/services/logger/std/std-out-logger.ts",
"chars": 3442,
"preview": "import * as chalk from 'chalk'\nimport { DeepstreamPlugin, DeepstreamLogger, DeepstreamServices, DeepstreamConfig, LOG_LE"
},
{
"path": "src/services/monitoring/combine-monitoring.ts",
"chars": 2138,
"preview": "import { DeepstreamPlugin, DeepstreamMonitoring, SocketData, LOG_LEVEL, EVENT, MetaData } from '@deepstream/types'\nimpor"
},
{
"path": "src/services/monitoring/http/monitoring-http.spec.ts",
"chars": 71,
"preview": "describe('stub', () => {\n it ('does nothing yet', () => {\n })\n})\n"
},
{
"path": "src/services/monitoring/http/monitoring-http.ts",
"chars": 2235,
"preview": "import { DeepstreamServices, DeepstreamHTTPMeta, DeepstreamHTTPResponse, EVENT } from '@deepstream/types'\nimport { Monit"
},
{
"path": "src/services/monitoring/log/monitoring-log.spec.ts",
"chars": 71,
"preview": "describe('stub', () => {\n it ('does nothing yet', () => {\n })\n})\n"
},
{
"path": "src/services/monitoring/log/monitoring-log.ts",
"chars": 1462,
"preview": "import { DeepstreamServices, NamespacedLogger } from '@deepstream/types'\nimport { MonitoringBase } from '../monitoring-b"
},
{
"path": "src/services/monitoring/monitoring-base.ts",
"chars": 3642,
"preview": "import { Message, ACTIONS } from '@deepstream/protobuf/dist/types/messages'\nimport { TOPIC, STATE_REGISTRY_TOPIC } from "
},
{
"path": "src/services/monitoring/noop-monitoring.ts",
"chars": 652,
"preview": "import { DeepstreamPlugin, DeepstreamMonitoring, SocketData, LOG_LEVEL, EVENT } from '@deepstream/types'\nimport { Messag"
},
{
"path": "src/services/permission/open/open-permission.spec.ts",
"chars": 575,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport { OpenPermission } from './open-permission'\n\ndescribe('open permiss"
},
{
"path": "src/services/permission/open/open-permission.ts",
"chars": 616,
"preview": "import { Message } from '../../../constants'\nimport { DeepstreamPlugin, DeepstreamPermission, PermissionCallback, Socket"
},
{
"path": "src/services/permission/valve/config-compiler.spec.ts",
"chars": 915,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nconst configCompiler = require('./config-compiler')\n\ndescribe('compiles use"
},
{
"path": "src/services/permission/valve/config-compiler.ts",
"chars": 948,
"preview": "import * as pathParser from './path-parser'\nimport * as ruleParser from './rule-parser'\nimport { ValveSchema } from '@de"
},
{
"path": "src/services/permission/valve/config-permission-basic.spec.ts",
"chars": 10614,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as C from '../../../constants'\nimport { getBasePermissions } from"
},
{
"path": "src/services/permission/valve/config-permission-create.spec.ts",
"chars": 1799,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as C from '../../../constants'\n\nimport { getBasePermissions } fro"
},
{
"path": "src/services/permission/valve/config-permission-cross-reference.spec.ts",
"chars": 7090,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as C from '../../../constants'\n\nimport { getBasePermissions } fro"
},
{
"path": "src/services/permission/valve/config-permission-load.spec.ts",
"chars": 3633,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport {spy, assert} from 'sinon'\nimport * as C from '../../../constants'\ni"
},
{
"path": "src/services/permission/valve/config-permission-nested-cross-reference.spec.ts",
"chars": 5805,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as testHelper from '../../../test/helper/test-helper'\nimport * as"
},
{
"path": "src/services/permission/valve/config-permission-other.spec.ts",
"chars": 2144,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport { getBasePermissions } from '../../../test/helper/test-helper'\nimpo"
},
{
"path": "src/services/permission/valve/config-permission-record-patch.spec.ts",
"chars": 3579,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as C from '../../../constants'\nimport * as testHelper from '../.."
},
{
"path": "src/services/permission/valve/config-permission.ts",
"chars": 5538,
"preview": "import * as configCompiler from './config-compiler'\nimport * as configValidator from './config-validator'\nimport RuleApp"
},
{
"path": "src/services/permission/valve/config-schema.ts",
"chars": 374,
"preview": "import { ConfigSchema } from '@deepstream/types'\n\nexport const SCHEMA: ConfigSchema = {\n record: {\n write: true,\n "
},
{
"path": "src/services/permission/valve/config-validator.spec.ts",
"chars": 2826,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as configValidator from './config-validator'\nimport * as testHelp"
},
{
"path": "src/services/permission/valve/config-validator.ts",
"chars": 3145,
"preview": "import { SCHEMA } from './config-schema'\nimport * as pathParser from './path-parser'\nimport * as ruleParser from './rule"
},
{
"path": "src/services/permission/valve/path-parser.spec.ts",
"chars": 3882,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport * as pathParser from './path-parser'\n\nconst isRegExp = function (va"
},
{
"path": "src/services/permission/valve/path-parser.ts",
"chars": 1435,
"preview": "const WILDCARD_REGEXP = /\\*/g\nconst WILDCARD_STRING = '.*'\nconst VARIABLE_REGEXP = /(\\$[a-zA-Z0-9]+)/g\nconst VARIABLE_ST"
},
{
"path": "src/services/permission/valve/rule-application.ts",
"chars": 11955,
"preview": "import { EOL } from 'os'\nimport { Message, RECORD_ACTION, PRESENCE_ACTION, EVENT_ACTION, RPC_ACTION, RecordData, TOPIC, "
},
{
"path": "src/services/permission/valve/rule-cache.spec.ts",
"chars": 2150,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nconst RuleCache = require('./rule-cache').default\n\ndescribe('loads and ret"
},
{
"path": "src/services/permission/valve/rule-cache.ts",
"chars": 2132,
"preview": "import { ValveConfig } from '@deepstream/types'\n\ninterface CachedRule {\n rule: string,\n isUsed: boolean,\n}\n\nexport def"
},
{
"path": "src/services/permission/valve/rule-parser.spec.ts",
"chars": 6788,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nconst ruleParser = require('./rule-parser')\n\ndescribe('validates rule stri"
},
{
"path": "src/services/permission/valve/rule-parser.ts",
"chars": 2871,
"preview": "import * as rulesMap from './rules-map'\nimport { ValveSection, RuleType } from './config-permission'\n\n// TODO: any of th"
},
{
"path": "src/services/permission/valve/rules-map.spec.ts",
"chars": 1586,
"preview": "import 'mocha'\nimport { expect } from 'chai'\n\nimport { getRulesForMessage } from './rules-map'\nimport * as C from '../.."
},
{
"path": "src/services/permission/valve/rules-map.ts",
"chars": 3861,
"preview": "import { Dictionary } from 'ts-essentials'\nimport { TOPIC, RECORD_ACTION, EVENT_ACTION, RPC_ACTION, PRESENCE_ACTION, Mes"
},
{
"path": "src/services/storage/noop-storage.spec.ts",
"chars": 945,
"preview": "import 'mocha'\nimport { expect } from 'chai'\nimport {spy} from 'sinon'\nimport { NoopStorage } from './noop-storage'\n\ndes"
},
{
"path": "src/services/storage/noop-storage.ts",
"chars": 722,
"preview": "import { DeepstreamPlugin, StorageWriteCallback, StorageReadCallback, DeepstreamStorage } from '@deepstream/types'\n\nexpo"
},
{
"path": "src/services/subscription-registry/default-subscription-registry-factory.ts",
"chars": 1211,
"preview": "import { DefaultSubscriptionRegistry } from './default-subscription-registry'\nimport { DeepstreamConfig, DeepstreamServi"
},
{
"path": "src/services/subscription-registry/default-subscription-registry.spec.ts",
"chars": 9224,
"preview": "import 'mocha'\nimport * as sinon from 'sinon'\nimport {expect} from 'chai'\nimport * as C from '../../constants'\nimport * "
},
{
"path": "src/services/subscription-registry/default-subscription-registry.ts",
"chars": 12933,
"preview": "import {\n EVENT_ACTION,\n PRESENCE_ACTION,\n RECORD_ACTION,\n RPC_ACTION,\n TOPIC,\n MONITORING_ACTION,\n Message,\n Bu"
},
{
"path": "src/services/telemetry/deepstreamio-telemetry.ts",
"chars": 3271,
"preview": "import { DeepstreamTelemetry, DeepstreamPlugin, DeepstreamServices, EVENT, DeepstreamConfig } from '@deepstream/types'\ni"
},
{
"path": "src/test/common.ts",
"chars": 89,
"preview": "import * as chai from 'chai'\nimport * as sinonChai from 'sinon-chai'\nchai.use(sinonChai)\n"
},
{
"path": "src/test/config/basic-permission-config.json",
"chars": 386,
"preview": "{\n \"presence\": {\n \"*\": {\n \"allow\": true\n }\n },\n \"record\": {\n \"*\": {\n "
},
{
"path": "src/test/config/basic-valid-json.json",
"chars": 20,
"preview": "{\n \"pet\": \"pug\"\n}"
},
{
"path": "src/test/config/blank-config.json",
"chars": 0,
"preview": ""
},
{
"path": "src/test/config/config-broken.js",
"chars": 36,
"preview": "/* eslint-disable */\nfoobarBreaksIt\n"
},
{
"path": "src/test/config/config-broken.yml",
"chars": 15,
"preview": "asdsad: ooops:\n"
},
{
"path": "src/test/config/config.js",
"chars": 34,
"preview": "module.exports = {\n port: 1002\n}\n"
},
{
"path": "src/test/config/config.yml",
"chars": 295,
"preview": "serverName: UUID\nport: 1337\nhost: 1.2.3.4\ncolors: false\nshowLogo: false\nlogLevel: ERROR\n\nmultipleenvs: '${EXAMPLE_HOST}:"
},
{
"path": "src/test/config/empty-map-config.json",
"chars": 2,
"preview": "{}"
},
{
"path": "src/test/config/exists-test/a-file.js",
"chars": 20,
"preview": "module.exports = {}\n"
},
{
"path": "src/test/config/exists-test/a-file.yml",
"chars": 20,
"preview": "---\nyup: thats right"
},
{
"path": "src/test/config/exists-test/a-json-file.json",
"chars": 20,
"preview": "{\n \"I\": \"exist\"\n}"
},
{
"path": "src/test/config/invalid-permission-conf.json",
"chars": 304,
"preview": "{\n \"presence\": {\n \"*\": {\n \"allow\": true\n }\n },\n \"record\": {},\n \"event\": {\n \""
},
{
"path": "src/test/config/invalid-user-config.json",
"chars": 172,
"preview": "{\n \"userA\": {\n \"password\": \"tsA+yfWGoEk9uEU/GX1JokkzteayLj6YFTwmraQrO7k=75KQ2Mzm\",\n \"serverData\": {}\n "
},
{
"path": "src/test/config/json-with-env-variables.json",
"chars": 259,
"preview": "{\n \"multipleenvs\": \"${EXAMPLE_HOST}:${EXAMPLE_PORT}\",\n \"environmentvariable\": \"${ENVIRONMENT_VARIABLE_TEST_1}\",\n "
},
{
"path": "src/test/config/no-private-events-permission-config.json",
"chars": 481,
"preview": "{\n \"presence\": {\n \"*\": {\n \"allow\": true\n }\n },\n \"record\": {\n \"*\": {\n "
},
{
"path": "src/test/config/sslKey.pem",
"chars": 9,
"preview": "I'm a key"
},
{
"path": "src/test/config/users-unhashed.json",
"chars": 249,
"preview": "{\n \"userC\": {\n \"password\": \"userCPass\",\n \"serverData\": { \"some\": \"values\" },\n \"clientData\": { \"a"
},
{
"path": "src/test/config/users.json",
"chars": 367,
"preview": "{\n \"userA\": {\n \"password\": \"CKgFpPLJX1+FezZR8bMsP+8wQR+WG0z7AZYRy9nz5KY=DzI79/e3yJ0Y0UvNENMXaQ==\",\n \"se"
},
{
"path": "src/test/helper/start-test-server.ts",
"chars": 270,
"preview": "const TestServer = require('./test-http-server')\nconst testServer = new TestServer(6004, () => {}, true)\n\ntestServer.on("
},
{
"path": "src/test/helper/test-helper.ts",
"chars": 5522,
"preview": "import * as SocketWrapperFactoryMock from '../mock/socket-wrapper-factory-mock'\nimport AuthenticationHandler from '../mo"
},
{
"path": "src/test/helper/test-http-server.ts",
"chars": 1993,
"preview": "import * as http from 'http'\nimport { EventEmitter } from 'events'\n\nexport default class TestHttpServer extends EventEmi"
},
{
"path": "src/test/helper/test-mocks.ts",
"chars": 2443,
"preview": "import { EventEmitter } from 'events'\nimport { Message, JSONObject } from '../../constants'\nimport { SocketWrapper } fro"
},
{
"path": "src/test/mock/authentication-handler-mock.ts",
"chars": 1608,
"preview": "import { DeepstreamPlugin, DeepstreamAuthentication, DeepstreamAuthenticationResult } from '@deepstream/types'\n\nexport d"
},
{
"path": "src/test/mock/http-mock.ts",
"chars": 1405,
"preview": "import { EventEmitter } from 'events'\n\nexport class HttpServerMock extends EventEmitter {\n public listening: boolean ="
},
{
"path": "src/test/mock/logger-mock.ts",
"chars": 1908,
"preview": "import {spy, SinonSpy} from 'sinon'\nimport { DeepstreamLogger, DeepstreamPlugin, LOG_LEVEL, NamespacedLogger, EVENT } fr"
},
{
"path": "src/test/mock/message-connector-mock.ts",
"chars": 2286,
"preview": "import { EventEmitter } from 'events'\nimport { DeepstreamPlugin, DeepstreamClusterNode } from '@deepstream/types'\nimport"
},
{
"path": "src/test/mock/permission-handler-mock.ts",
"chars": 939,
"preview": "import { PermissionCallback, SocketWrapper, DeepstreamPlugin } from '@deepstream/types'\nimport { Message } from '../../c"
},
{
"path": "src/test/mock/plugin-mock.ts",
"chars": 715,
"preview": "import { DeepstreamPlugin, DeepstreamServices, DeepstreamConfig } from '@deepstream/types'\nimport { EventEmitter } from "
}
]
// ... and 54 more files (download for full content)
About this extraction
This page contains the full source code of the deepstreamIO/deepstream.io GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 254 files (1.0 MB), approximately 259.3k tokens, and a symbol index with 1125 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.