@bopen-io/messagebox-server 1.1.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +11 -0
- package/.env.example +11 -0
- package/.eslintignore +2 -0
- package/.gcloudignore +17 -0
- package/.gitattributes +2 -0
- package/.github/workflows/build-and-push.yml +51 -0
- package/.github/workflows/deploy.yaml.example +64 -0
- package/.github/workflows/image.yaml +66 -0
- package/.vscode/launch.json +67 -0
- package/AGENTS.md +92 -0
- package/BASELINE.md +55 -0
- package/DEPLOYING.md +120 -0
- package/Dockerfile +63 -0
- package/docker-compose.yml +64 -0
- package/jest.config.integration.ts +26 -0
- package/jest.config.mjs +42 -0
- package/jest.config.ts +35 -0
- package/jest.setup.mjs +18 -0
- package/nginx.conf +36 -0
- package/package.json +65 -51
- package/scripts/build.js +19 -0
- package/scripts/mkenv.sh +31 -0
- package/scripts/start.sh +16 -0
- package/src/__tests/compose.test.ts +30 -0
- package/src/app.ts +210 -0
- package/src/compose.ts +286 -0
- package/src/config/firebase.ts +183 -0
- package/src/context.ts +49 -0
- package/src/index.ts +375 -0
- package/src/routes/__tests/acknowledgeMessage.test.ts +158 -0
- package/src/routes/__tests/listMessages.test.ts +240 -0
- package/src/routes/__tests/sendMessage.test.ts +362 -0
- package/src/routes/acknowledgeMessage.ts +153 -0
- package/src/routes/index.ts +17 -0
- package/src/routes/listDevices.ts +80 -0
- package/src/routes/listMessages.ts +195 -0
- package/src/routes/permissions/getPermission.ts +152 -0
- package/src/routes/permissions/getQuote.ts +192 -0
- package/src/routes/permissions/index.ts +12 -0
- package/src/routes/permissions/listPermissions.ts +202 -0
- package/src/routes/permissions/setPermission.ts +155 -0
- package/src/routes/registerDevice.ts +155 -0
- package/src/routes/sendMessage.ts +531 -0
- package/src/runtimeDeps.ts +29 -0
- package/src/swagger.ts +54 -0
- package/src/telemetry.ts +158 -0
- package/src/types/messagePermissions.ts +18 -0
- package/src/types/mock-knex.d.ts +18 -0
- package/src/types/notifications.ts +27 -0
- package/src/utils/logger.ts +92 -0
- package/src/utils/messagePermissions.ts +148 -0
- package/src/utils/sendFCMNotification.ts +143 -0
- package/tsconfig.json +36 -0
- package/tsconfig.types.json +11 -0
- package/out/knexfile.js +0 -25
- package/out/knexfile.js.map +0 -1
- package/out/src/app.js +0 -160
- package/out/src/app.js.map +0 -1
- package/out/src/config/firebase.js +0 -150
- package/out/src/config/firebase.js.map +0 -1
- package/out/src/index.js +0 -295
- package/out/src/index.js.map +0 -1
- package/out/src/migrations/2022-12-28-001-initial-migration.js +0 -28
- package/out/src/migrations/2022-12-28-001-initial-migration.js.map +0 -1
- package/out/src/migrations/2023-01-17-messages-update.js +0 -11
- package/out/src/migrations/2023-01-17-messages-update.js.map +0 -1
- package/out/src/migrations/2024-03-05-001-messageID-upgrade.js +0 -21
- package/out/src/migrations/2024-03-05-001-messageID-upgrade.js.map +0 -1
- package/out/src/migrations/2025-01-31-001-notification-permissions.js +0 -59
- package/out/src/migrations/2025-01-31-001-notification-permissions.js.map +0 -1
- package/out/src/migrations/2025-01-31-002-device-registrations.js +0 -24
- package/out/src/migrations/2025-01-31-002-device-registrations.js.map +0 -1
- package/out/src/routes/__tests/acknowledgeMessage.test.js +0 -129
- package/out/src/routes/__tests/acknowledgeMessage.test.js.map +0 -1
- package/out/src/routes/__tests/listMessages.test.js +0 -211
- package/out/src/routes/__tests/listMessages.test.js.map +0 -1
- package/out/src/routes/__tests/sendMessage.test.js +0 -307
- package/out/src/routes/__tests/sendMessage.test.js.map +0 -1
- package/out/src/routes/acknowledgeMessage.js +0 -144
- package/out/src/routes/acknowledgeMessage.js.map +0 -1
- package/out/src/routes/index.js +0 -17
- package/out/src/routes/index.js.map +0 -1
- package/out/src/routes/listDevices.js +0 -74
- package/out/src/routes/listDevices.js.map +0 -1
- package/out/src/routes/listMessages.js +0 -186
- package/out/src/routes/listMessages.js.map +0 -1
- package/out/src/routes/permissions/getPermission.js +0 -149
- package/out/src/routes/permissions/getPermission.js.map +0 -1
- package/out/src/routes/permissions/getQuote.js +0 -165
- package/out/src/routes/permissions/getQuote.js.map +0 -1
- package/out/src/routes/permissions/index.js +0 -12
- package/out/src/routes/permissions/index.js.map +0 -1
- package/out/src/routes/permissions/listPermissions.js +0 -190
- package/out/src/routes/permissions/listPermissions.js.map +0 -1
- package/out/src/routes/permissions/setPermission.js +0 -137
- package/out/src/routes/permissions/setPermission.js.map +0 -1
- package/out/src/routes/registerDevice.js +0 -150
- package/out/src/routes/registerDevice.js.map +0 -1
- package/out/src/routes/sendMessage.js +0 -451
- package/out/src/routes/sendMessage.js.map +0 -1
- package/out/src/swagger.js +0 -49
- package/out/src/swagger.js.map +0 -1
- package/out/src/types/messagePermissions.js +0 -2
- package/out/src/types/messagePermissions.js.map +0 -1
- package/out/src/types/notifications.js +0 -2
- package/out/src/types/notifications.js.map +0 -1
- package/out/src/utils/logger.js +0 -24
- package/out/src/utils/logger.js.map +0 -1
- package/out/src/utils/messagePermissions.js +0 -126
- package/out/src/utils/messagePermissions.js.map +0 -1
- package/out/src/utils/sendFCMNotification.js +0 -121
- package/out/src/utils/sendFCMNotification.js.map +0 -1
- package/out/tsconfig.tsbuildinfo +0 -1
package/.dockerignore
ADDED
package/.env.example
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
NODE_ENV=development
|
|
2
|
+
HOSTING_DOMAIN="http://localhost:8080"
|
|
3
|
+
ROUTING_PREFIX=""
|
|
4
|
+
SERVER_PRIVATE_KEY='0209cb3b54d5099acaa8ced2deebf2539fe8771c014a09057372c6bc671bfb9067' # Example key, use your own key in production!!
|
|
5
|
+
MIGRATE_KEY="my-grate-key"
|
|
6
|
+
|
|
7
|
+
# Firebase push notifications (optional — defaults to disabled)
|
|
8
|
+
ENABLE_FIREBASE=false
|
|
9
|
+
# FIREBASE_PROJECT_ID=your-project-id
|
|
10
|
+
# FIREBASE_SERVICE_ACCOUNT_JSON={"type":"service_account",...}
|
|
11
|
+
# FIREBASE_SERVICE_ACCOUNT_PATH=/path/to/serviceAccount.json
|
package/.eslintignore
ADDED
package/.gcloudignore
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# This file specifies files that are *not* uploaded to Google Cloud Platform
|
|
2
|
+
# using gcloud. It follows the same syntax as .gitignore, with the addition of
|
|
3
|
+
# "#!include" directives (which insert the entries of the given .gitignore-style
|
|
4
|
+
# file at that point).
|
|
5
|
+
#
|
|
6
|
+
# For more information, run:
|
|
7
|
+
# $ gcloud topic gcloudignore
|
|
8
|
+
#
|
|
9
|
+
.gcloudignore
|
|
10
|
+
# If you would like to upload your .git directory, .gitignore file or files
|
|
11
|
+
# from your .gitignore file, remove the corresponding line
|
|
12
|
+
# below:
|
|
13
|
+
.git
|
|
14
|
+
.gitignore
|
|
15
|
+
|
|
16
|
+
# Node.js dependencies:
|
|
17
|
+
node_modules/
|
package/.gitattributes
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Build and Push to AWS Marketplace ECR
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: 'Version tag (e.g., 1.0.0)'
|
|
8
|
+
required: true
|
|
9
|
+
default: '1.0.0'
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
|
18
|
+
|
|
19
|
+
- name: Configure AWS credentials
|
|
20
|
+
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502
|
|
21
|
+
with:
|
|
22
|
+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
23
|
+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
24
|
+
aws-region: us-east-1
|
|
25
|
+
|
|
26
|
+
- name: Login to Amazon ECR
|
|
27
|
+
run: |
|
|
28
|
+
aws ecr get-login-password --region us-east-1 | \
|
|
29
|
+
docker login --username AWS --password-stdin \
|
|
30
|
+
709825985650.dkr.ecr.us-east-1.amazonaws.com
|
|
31
|
+
|
|
32
|
+
- name: Build Docker image
|
|
33
|
+
run: |
|
|
34
|
+
docker build --platform linux/amd64 -t message-box-server:${{ github.event.inputs.version }} .
|
|
35
|
+
|
|
36
|
+
- name: Tag image
|
|
37
|
+
run: |
|
|
38
|
+
docker tag message-box-server:${{ github.event.inputs.version }} \
|
|
39
|
+
709825985650.dkr.ecr.us-east-1.amazonaws.com/bsv-blockchain/message-box-server:${{ github.event.inputs.version }}
|
|
40
|
+
|
|
41
|
+
- name: Push to ECR
|
|
42
|
+
run: |
|
|
43
|
+
docker push 709825985650.dkr.ecr.us-east-1.amazonaws.com/bsv-blockchain/message-box-server:${{ github.event.inputs.version }}
|
|
44
|
+
|
|
45
|
+
- name: Verify push
|
|
46
|
+
run: |
|
|
47
|
+
aws ecr describe-images \
|
|
48
|
+
--registry-id 709825985650 \
|
|
49
|
+
--repository-name bsv-blockchain/message-box-server \
|
|
50
|
+
--region us-east-1 \
|
|
51
|
+
--image-ids imageTag=${{ github.event.inputs.version }}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Deployment
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- master
|
|
6
|
+
- production
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
CURRENT_BRANCH: ${{ github.ref_name == 'production' && 'production' || 'master' }}
|
|
10
|
+
GCR_HOST: us.gcr.io
|
|
11
|
+
GOOGLE_PROJECT_ID: example-project-id
|
|
12
|
+
GCR_IMAGE_NAME: messagebox-server
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
name: Deploy
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- name: Check out code
|
|
20
|
+
uses: actions/checkout@v2
|
|
21
|
+
|
|
22
|
+
- name: Setup Node.js
|
|
23
|
+
uses: actions/setup-node@v3
|
|
24
|
+
with:
|
|
25
|
+
node-version: 22
|
|
26
|
+
|
|
27
|
+
- name: Install Dependencies
|
|
28
|
+
run: npm ci
|
|
29
|
+
|
|
30
|
+
- name: Push Docker Image to GCR
|
|
31
|
+
uses: RafikFarhad/push-to-gcr-github-action@v4.1
|
|
32
|
+
with:
|
|
33
|
+
gcloud_service_key: ${{ secrets.DOCKER_REGISTRY_PUSH_KEY }}
|
|
34
|
+
registry: ${{ env.GCR_HOST }}
|
|
35
|
+
project_id: ${{ env.GOOGLE_PROJECT_ID }}
|
|
36
|
+
image_name: ${{ env.GCR_IMAGE_NAME }}
|
|
37
|
+
image_tag: latest,${{ env.CURRENT_BRANCH }}-${{ github.sha }}
|
|
38
|
+
|
|
39
|
+
- name: Create Service Description File
|
|
40
|
+
run: ./scripts/mkenv.sh service.${{ env.CURRENT_BRANCH }}.yaml
|
|
41
|
+
env:
|
|
42
|
+
IMAGE: "${{ env.GCR_HOST }}/${{ env.GOOGLE_PROJECT_ID }}/${{ env.GCR_IMAGE_NAME }}:${{ env.CURRENT_BRANCH }}-${{ github.sha }}"
|
|
43
|
+
SERVICE: ${{ env.CURRENT_BRANCH == 'production' && 'prod-messagebox-server' || 'staging-messagebox-server' }}
|
|
44
|
+
BSV_NETWORK: ${{ env.CURRENT_BRANCH == 'production' && 'mainnet' || 'testnet' }}
|
|
45
|
+
NODE_ENV: ${{ env.CURRENT_BRANCH =='production' && 'production' || 'staging' }}
|
|
46
|
+
WALLET_STORAGE_URL: ${{ env.CURRENT_BRANCH == 'production' && secrets.PROD_WALLET_STORAGE_URL || secrets.STAGING_WALLET_STORAGE_URL }}
|
|
47
|
+
SERVER_PRIVATE_KEY: ${{ env.CURRENT_BRANCH == 'production' && secrets.PROD_SERVER_PRIVATE_KEY || secrets.STAGING_SERVER_PRIVATE_KEY }}
|
|
48
|
+
KNEX_DB_CONNECTION: ${{ env.CURRENT_BRANCH == 'production' && secrets.PROD_KNEX_DB_CONNECTION || secrets.STAGING_KNEX_DB_CONNECTION }}
|
|
49
|
+
LOGGING_ENABLED: ${{ env.CURRENT_BRANCH == 'production' && secrets.PROD_LOGGING_ENABLED || secrets.STAGING_LOGGING_ENABLED }}
|
|
50
|
+
- name: Authenticate to Google Cloud
|
|
51
|
+
uses: google-github-actions/auth@v1
|
|
52
|
+
with:
|
|
53
|
+
credentials_json: ${{ secrets.gcp_deploy_creds }}
|
|
54
|
+
|
|
55
|
+
- name: Deploy to Cloud Run
|
|
56
|
+
uses: google-github-actions/deploy-cloudrun@v1
|
|
57
|
+
with:
|
|
58
|
+
metadata: "service.${{ env.CURRENT_BRANCH }}.yaml"
|
|
59
|
+
region: us-west1
|
|
60
|
+
|
|
61
|
+
- name: Set Min Instances and Enable CPU Boost
|
|
62
|
+
run: |
|
|
63
|
+
gcloud run services update ${{ env.CURRENT_BRANCH == 'production' && 'prod-storage' || 'staging-storage' }} \
|
|
64
|
+
--min-instances=1 --cpu-boost --region=us-west1
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Build and push OCI image to Docker Hub
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check-current-branch:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
outputs:
|
|
12
|
+
branch: ${{ steps.check_step.outputs.branch }}
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- name: Get current branch
|
|
20
|
+
id: check_step
|
|
21
|
+
# 1. Get the list of branches ref where this tag exists
|
|
22
|
+
# 2. Remove 'origin/' from that result
|
|
23
|
+
# 3. Put that string in output
|
|
24
|
+
run: |
|
|
25
|
+
raw=$(git branch -r --contains ${{ github.ref }})
|
|
26
|
+
branch="$(echo ${raw//origin\//} | tr -d '\n')"
|
|
27
|
+
echo "{name}=branch" >> $GITHUB_OUTPUT
|
|
28
|
+
echo "Branches where this tag exists : $branch."
|
|
29
|
+
|
|
30
|
+
image:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
needs: check-current-branch
|
|
33
|
+
if: contains(${{ needs.check.outputs.branch }}, 'main')`
|
|
34
|
+
steps:
|
|
35
|
+
- name: Check out the repo
|
|
36
|
+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
37
|
+
|
|
38
|
+
- name: Get build args
|
|
39
|
+
id: build_args
|
|
40
|
+
run: |
|
|
41
|
+
echo "APP_COMMIT=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
|
42
|
+
echo "APP_VERSION=$(git describe --tags --always --abbrev=0 --match='v[0-9]*.[0-9]*.[0-9]*' 2> /dev/null | sed 's/^.//')" >> "$GITHUB_OUTPUT"
|
|
43
|
+
|
|
44
|
+
- name: Log in to Docker Hub
|
|
45
|
+
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
|
46
|
+
with:
|
|
47
|
+
username: ${{ secrets.DOCKER_USERNAME }}
|
|
48
|
+
password: ${{ secrets.DOCKER_PASSWORD }}
|
|
49
|
+
|
|
50
|
+
- name: Extract metadata (tags, labels)
|
|
51
|
+
id: meta
|
|
52
|
+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
|
|
53
|
+
with:
|
|
54
|
+
images: bsvb/message-box-server
|
|
55
|
+
|
|
56
|
+
- name: Build and push image
|
|
57
|
+
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
|
|
58
|
+
with:
|
|
59
|
+
context: .
|
|
60
|
+
file: ./Dockerfile
|
|
61
|
+
push: true
|
|
62
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
63
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
64
|
+
build-args: |
|
|
65
|
+
APP_COMMIT=${{ steps.build_args.outputs.APP_COMMIT }}
|
|
66
|
+
APP_VERSION=${{ steps.build_args.outputs.APP_VERSION }}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "default",
|
|
9
|
+
"type": "node",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
"skipFiles": [
|
|
12
|
+
"<node_internals>/**"
|
|
13
|
+
],
|
|
14
|
+
"program": "${workspaceFolder}/lib/index.js",
|
|
15
|
+
"outFiles": [
|
|
16
|
+
"${workspaceFolder}/**/*.js"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "Launch",
|
|
21
|
+
"type": "node",
|
|
22
|
+
"program": "${workspaceFolder}/src/index.ts",
|
|
23
|
+
"request": "launch",
|
|
24
|
+
"stopOnEntry": false,
|
|
25
|
+
"args": [],
|
|
26
|
+
"cwd": "${workspaceFolder}/.",
|
|
27
|
+
"runtimeExecutable": null,
|
|
28
|
+
"runtimeArgs": [
|
|
29
|
+
"--nolazy"
|
|
30
|
+
],
|
|
31
|
+
"env": {
|
|
32
|
+
"NODE_ENV": "development"
|
|
33
|
+
},
|
|
34
|
+
"console": "integratedTerminal",
|
|
35
|
+
"sourceMaps": true,
|
|
36
|
+
"outFiles": [
|
|
37
|
+
"${workspaceFolder}/**/*.js"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "node",
|
|
42
|
+
"request": "launch",
|
|
43
|
+
"name": "Jest Current Tests",
|
|
44
|
+
"program": "${workspaceFolder}/node_modules/.bin/jest",
|
|
45
|
+
"args": [
|
|
46
|
+
"--runTestsByPath",
|
|
47
|
+
"${relativeFile}"
|
|
48
|
+
],
|
|
49
|
+
"console": "integratedTerminal",
|
|
50
|
+
"internalConsoleOptions": "neverOpen",
|
|
51
|
+
"sourceMaps": true,
|
|
52
|
+
"windows": {
|
|
53
|
+
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"type": "node",
|
|
58
|
+
"request": "attach",
|
|
59
|
+
"name": "Attach to Node Process",
|
|
60
|
+
"port": 9229,
|
|
61
|
+
"restart": true,
|
|
62
|
+
"skipFiles": ["<node_internals>/**"],
|
|
63
|
+
"sourceMaps": true
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
}
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# CLAUDE.md — Message Box Server
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
A secure peer-to-peer message routing server for the Bitcoin SV ecosystem. Provides identity-based message delivery, real-time WebSocket communication, and full mutual authentication using BRC-103 signatures. Messages are encrypted and stored until acknowledged, supporting both HTTP and WebSocket transports.
|
|
5
|
+
|
|
6
|
+
## Service surface
|
|
7
|
+
- **POST /sendMessage** – Send encrypted message to a recipient's message box
|
|
8
|
+
- **POST /listMessages** – List all unacknowledged messages in a box (authenticated)
|
|
9
|
+
- **POST /acknowledgeMessage** – Mark messages as read/delete them (authenticated)
|
|
10
|
+
- **WebSocket** – Real-time authenticated messaging over `@bsv/authsocket` using rooms in format `{identityKey}-{messageBox}`
|
|
11
|
+
- Events: `authenticated`, `joinRoom`, `sendMessage`, `leaveRoom`
|
|
12
|
+
- **Background jobs** – Firebase push notifications (optional, enabled via ENABLE_FIREBASE)
|
|
13
|
+
|
|
14
|
+
## Real deployment
|
|
15
|
+
- **Dockerfile** – Multi-stage build: node:20-alpine builder → production runtime with nginx reverse proxy on port 8080 (app runs on 3000, nginx on 8080)
|
|
16
|
+
- **docker-compose.yml** – Backend (Node), MySQL 8.0, PHPMyAdmin. MySQL connection pool with health checks
|
|
17
|
+
- **knexfile.ts** – MySQL 8.0 via mysql2, default connection string configurable via KNEX_DB_CONNECTION
|
|
18
|
+
- **nginx.conf** – HTTP/2 reverse proxy listening on 8080, proxying to localhost:3000, gzip enabled, 1GB max body size
|
|
19
|
+
- **Migrations** – Knex migrations stored in `src/migrations/`:
|
|
20
|
+
- `2022-12-28-001-initial-migration.ts` – Core messages table with identity keys
|
|
21
|
+
- `2023-01-17-messages-update.ts` – Payload storage updates
|
|
22
|
+
- `2024-03-05-001-messageID-upgrade.ts` – MessageID uniqueness constraints
|
|
23
|
+
- `2025-01-31-001-notification-permissions.ts` – Firebase notification permissions
|
|
24
|
+
- `2025-01-31-002-device-registrations.ts` – Device registration tracking
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
Environment variables (from `.env.example`):
|
|
28
|
+
- **NODE_ENV** – `development`, `staging`, or `production`
|
|
29
|
+
- **PORT** – Express port (default 3000 prod, 8080 dev)
|
|
30
|
+
- **HTTP_PORT** – Alternative port alias
|
|
31
|
+
- **HOSTING_DOMAIN** – Public domain for overlay advertisement (e.g., `http://localhost:8080`)
|
|
32
|
+
- **SERVER_PRIVATE_KEY** – 256-bit hex private key for server identity and auth signing (required)
|
|
33
|
+
- **ROUTING_PREFIX** – Optional path prefix for all routes (e.g., `/api`)
|
|
34
|
+
- **ENABLE_WEBSOCKETS** – Set to `'true'` to enable real-time messaging (default true)
|
|
35
|
+
- **LOGGING_ENABLED** – Set to `'true'` for verbose debug logging
|
|
36
|
+
- **WALLET_STORAGE_URL** – URL of wallet storage service (e.g., `https://storage.babbage.systems`)
|
|
37
|
+
- **KNEX_DB_CLIENT** – Database client (default: `mysql`)
|
|
38
|
+
- **KNEX_DB_CONNECTION** – JSON connection config: `{"host":"localhost","port":3306,"user":"root","password":"...","database":"messagebox-backend"}`
|
|
39
|
+
- **MIGRATE_KEY** – Optional key to authorize migration operations
|
|
40
|
+
- **ENABLE_FIREBASE** – Set to `'true'` to enable Firebase push notifications
|
|
41
|
+
- **FIREBASE_PROJECT_ID** – GCP project ID for Firebase
|
|
42
|
+
- **FIREBASE_SERVICE_ACCOUNT_JSON** – Firebase service account JSON (inline)
|
|
43
|
+
- **FIREBASE_SERVICE_ACCOUNT_PATH** – Path to Firebase service account JSON file
|
|
44
|
+
|
|
45
|
+
## Dependencies
|
|
46
|
+
- **Database** – MySQL 8.0 via knex + mysql2
|
|
47
|
+
- **@bsv packages**
|
|
48
|
+
- `@bsv/sdk` – Cryptography, key handling
|
|
49
|
+
- `@bsv/auth-express-middleware` – BRC-103 request/response authentication
|
|
50
|
+
- `@bsv/authsocket` – Authenticated WebSocket server
|
|
51
|
+
- `@bsv/payment-express-middleware` – Optional payment verification
|
|
52
|
+
- `@bsv/wallet-toolbox` – Wallet operations
|
|
53
|
+
- **External services**
|
|
54
|
+
- Wallet Storage (via `WALLET_STORAGE_URL`) – Stores key derivation metadata
|
|
55
|
+
- Firebase Admin SDK (optional) – Push notifications to registered devices
|
|
56
|
+
- **Key packages** – Express, body-parser, dotenv, socket.io (WebSocket), web-push, firebase-admin, swagger-jsdoc
|
|
57
|
+
|
|
58
|
+
## Operational concerns
|
|
59
|
+
- **Local dev** – `npm run dev` with hot-reload via nodemon, requires MySQL running (use docker-compose)
|
|
60
|
+
- **Production** – `npm run build && npm start` compiles TypeScript to `out/`, then `node out/src/index.js` starts
|
|
61
|
+
- **Migrations** – Auto-run after server starts (5s delay in code); use `MIGRATE_KEY` to authorize if needed
|
|
62
|
+
- **Health endpoint** – No explicit health check route; monitor WebSocket and HTTP endpoints
|
|
63
|
+
- **Scaling** – Single instance by design; WebSocket rooms are in-memory, horizontal scaling requires sticky sessions or external message broker
|
|
64
|
+
- **Database** – MySQL 8.0 required; note query performance with large message volumes (index on identity keys + messageBox)
|
|
65
|
+
- **WebSocket** – `@bsv/authsocket` handles multiplexing; each client connects once but can join multiple rooms
|
|
66
|
+
|
|
67
|
+
## Spec conformance
|
|
68
|
+
- **BRC-103** – Mutual authentication on all requests and WebSocket handshakes
|
|
69
|
+
- **BRC-2** – Optional AES-encrypted message payloads (client-side encryption supported)
|
|
70
|
+
- **SHIP** – Overlay advertisement via `@bsv/sdk` PublicKey operations
|
|
71
|
+
- **MessageBox protocol** – Custom identity + messageBox type routing model
|
|
72
|
+
|
|
73
|
+
## Integration points
|
|
74
|
+
- **@bsv/messagebox-client** – Client library that connects to this server, handles auth, encryption, WebSocket
|
|
75
|
+
- **Wallet Storage** – Derives keys from SERVER_PRIVATE_KEY via configured wallet storage endpoint
|
|
76
|
+
- **Overlay nodes** – Can advertise MessageBox capabilities via SHIP protocol using HOSTING_DOMAIN
|
|
77
|
+
- **Payment processing** – Optionally enforces BRC-100 payment verification on message send (via `@bsv/payment-express-middleware`)
|
|
78
|
+
|
|
79
|
+
## File map
|
|
80
|
+
- **src/**
|
|
81
|
+
- `index.ts` – Entry point: loads env, creates HTTP + WebSocket servers, starts migrations
|
|
82
|
+
- `app.ts` – Express app setup, route mounting, auth middleware
|
|
83
|
+
- `routes/` – HTTP endpoints: `sendMessage.ts`, `listMessages.ts`, `acknowledgeMessage.ts`, device listing, permissions
|
|
84
|
+
- `config/firebase.ts` – Firebase Admin SDK initialization
|
|
85
|
+
- `utils/` – Helpers: logger, notification sending, message permissions
|
|
86
|
+
- `migrations/` – Knex schema migrations for messages, permissions, devices
|
|
87
|
+
- `types/` – TypeScript interfaces for notifications, permissions
|
|
88
|
+
- **knexfile.ts** – Knex configuration, driver selection, connection pooling
|
|
89
|
+
- **Dockerfile** – Multi-stage Node + nginx container
|
|
90
|
+
- **docker-compose.yml** – Services: backend, MySQL, PHPMyAdmin
|
|
91
|
+
- **nginx.conf** – Reverse proxy config
|
|
92
|
+
- **.env.example** – Template with all required/optional variables
|
package/BASELINE.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# BASELINE — @bsv/messagebox-server
|
|
2
|
+
|
|
3
|
+
> Captured: 2026-04-24. Reflects state at time of ts-stack migration.
|
|
4
|
+
|
|
5
|
+
## Identity
|
|
6
|
+
| Field | Value |
|
|
7
|
+
|-------|-------|
|
|
8
|
+
| Package | `@bsv/messagebox-server` |
|
|
9
|
+
| Path | `packages/messaging/message-box-server` |
|
|
10
|
+
| npm | private — not published |
|
|
11
|
+
| Version | 1.1.5 |
|
|
12
|
+
| Criticality | **Tier 2** — private messaging service; failure isolates to message delivery domain |
|
|
13
|
+
| Reliability Level | **RL1** — builds, 3 test files, coverage tooling present but coverage unknown |
|
|
14
|
+
| Owner | @sirdeggen |
|
|
15
|
+
| Backup owner | — |
|
|
16
|
+
|
|
17
|
+
## Build
|
|
18
|
+
| Field | Value |
|
|
19
|
+
|-------|-------|
|
|
20
|
+
| Build command | `tsc` |
|
|
21
|
+
| Build status | ✅ Passing (assumed — not yet verified in ts-stack CI) |
|
|
22
|
+
| Outputs | Compiled JS (ESM via tsc) |
|
|
23
|
+
|
|
24
|
+
## Tests
|
|
25
|
+
| Field | Value |
|
|
26
|
+
|-------|-------|
|
|
27
|
+
| Test command | `node --experimental-vm-modules node_modules/jest/bin/jest.js --config=jest.config.mjs` |
|
|
28
|
+
| Test files | 3 |
|
|
29
|
+
| Coverage command | `node --experimental-vm-modules node_modules/jest/bin/jest.js --config=jest.config.mjs --coverage --coverageReporters=text --coverageReporters=html` |
|
|
30
|
+
| Coverage | Not yet captured as baseline |
|
|
31
|
+
| Known flaky | None identified |
|
|
32
|
+
|
|
33
|
+
## Lint
|
|
34
|
+
| Field | Value |
|
|
35
|
+
|-------|-------|
|
|
36
|
+
| Linter | ts-standard |
|
|
37
|
+
| Lint command | `ts-standard --fix .` |
|
|
38
|
+
|
|
39
|
+
## Dependencies
|
|
40
|
+
| Type | Count | Packages |
|
|
41
|
+
|------|-------|---------|
|
|
42
|
+
| Production | 16 | @bsv/auth-express-middleware, @bsv/authsocket, @bsv/payment-express-middleware, @bsv/sdk, @bsv/wallet-toolbox, body-parser, dotenv, express, firebase-admin, knex, mongodb, mysql2, prettyjson, swagger-jsdoc, swagger-ui-express, web-push |
|
|
43
|
+
|
|
44
|
+
## Known Issues & Incidents
|
|
45
|
+
- Private package — not published to npm.
|
|
46
|
+
- Service, not a library; requires database and external dependencies at runtime.
|
|
47
|
+
- Uses `--experimental-vm-modules` flag for Jest ESM support.
|
|
48
|
+
|
|
49
|
+
## Migration Gate Checklist (MBGA §13.3)
|
|
50
|
+
- [x] BASELINE.md captured
|
|
51
|
+
- [ ] Conformance runner vectors passing
|
|
52
|
+
- [ ] Contract tests green
|
|
53
|
+
- [ ] Publishing rehearsed (npm dry-run)
|
|
54
|
+
- [ ] Rollback documented
|
|
55
|
+
- [ ] 60-day deprecation notice in source repo
|
package/DEPLOYING.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# MessageBox Server Deployment Guide
|
|
2
|
+
This guide covers how to deploy the MessageBox Server — a secure peer-to-peer message relay supporting authenticated HTTP and WebSocket communication and encrypted payloads.
|
|
3
|
+
________________________________________
|
|
4
|
+
### Overview
|
|
5
|
+
The MessageBox Server is a node-based Express server that enables identity-authenticated messaging over HTTP and WebSocket. Key features:
|
|
6
|
+
- Authenticated message sending and receiving
|
|
7
|
+
- Message box creation and routing by identity key
|
|
8
|
+
- WebSocket-based real-time delivery
|
|
9
|
+
- AES-encrypted message payloads (handled by clients)
|
|
10
|
+
________________________________________
|
|
11
|
+
### Requirements
|
|
12
|
+
- Node.js v18 or higher
|
|
13
|
+
- MySQL v8 or higher
|
|
14
|
+
- Docker (optional for local setup)
|
|
15
|
+
- A valid SERVER_PRIVATE_KEY - a 256-bit hex private key
|
|
16
|
+
- Wallet Storage instance URL (e.g., https://wallet-storage.babbage.systems)
|
|
17
|
+
________________________________________
|
|
18
|
+
### Project Structure
|
|
19
|
+
```bash
|
|
20
|
+
.
|
|
21
|
+
├── src/ # Server source files (Express app, routes, WebSocket, logger)
|
|
22
|
+
├── knexfile.js # DB connection settings
|
|
23
|
+
├── app.ts # Express and route setup
|
|
24
|
+
├── index.ts # Server entry point with WebSocket support
|
|
25
|
+
├── .env # Environment variable configuration
|
|
26
|
+
└── ...
|
|
27
|
+
```
|
|
28
|
+
________________________________________
|
|
29
|
+
### Required Environment Variables
|
|
30
|
+
|
|
31
|
+
Create a .env file in the root with the following:
|
|
32
|
+
|
|
33
|
+
```env
|
|
34
|
+
NODE_ENV=production
|
|
35
|
+
SERVER_PRIVATE_KEY=your_hex_64_char_key
|
|
36
|
+
WALLET_STORAGE_URL=https://wallet-storage.babbage.systems
|
|
37
|
+
ENABLE_WEBSOCKETS=true
|
|
38
|
+
PORT=5001
|
|
39
|
+
ROUTING_PREFIX=
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Optional:
|
|
43
|
+
|
|
44
|
+
```env
|
|
45
|
+
LOGGING_ENABLED=true
|
|
46
|
+
SKIP_NGINX=true # Set to skip auto-starting nginx in production
|
|
47
|
+
```
|
|
48
|
+
________________________________________
|
|
49
|
+
### Deployment Steps
|
|
50
|
+
**Local Development**
|
|
51
|
+
1. Install dependencies:
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
```
|
|
55
|
+
2. Start MySQL database (you can use Docker or your local MySQL):
|
|
56
|
+
- If using Docker:
|
|
57
|
+
```bash
|
|
58
|
+
docker compose up --build
|
|
59
|
+
```
|
|
60
|
+
- Otherwise, ensure a database is running and matches your knexfile.js.
|
|
61
|
+
3. Set up environment variables:
|
|
62
|
+
```bash
|
|
63
|
+
cp .env.example .env
|
|
64
|
+
# Fill in actual values
|
|
65
|
+
```
|
|
66
|
+
4. Run migrations:
|
|
67
|
+
```bash
|
|
68
|
+
npm run migrate
|
|
69
|
+
```
|
|
70
|
+
5. Start the server in development mode:
|
|
71
|
+
```bash
|
|
72
|
+
npm run dev
|
|
73
|
+
```
|
|
74
|
+
Server will run at http://localhost:5001
|
|
75
|
+
________________________________________
|
|
76
|
+
### Production Deployment
|
|
77
|
+
1. Ensure production .env is configured correctly
|
|
78
|
+
2. Build the project (if applicable):
|
|
79
|
+
```bash
|
|
80
|
+
npm run build
|
|
81
|
+
```
|
|
82
|
+
3. Run the server:
|
|
83
|
+
```bash
|
|
84
|
+
npm start
|
|
85
|
+
```
|
|
86
|
+
4. Optionally, configure nginx to reverse proxy to the server. Nginx will start automatically unless SKIP_NGINX=true is set.
|
|
87
|
+
________________________________________
|
|
88
|
+
### WebSocket Support
|
|
89
|
+
WebSocket support is enabled by default unless ENABLE_WEBSOCKETS=false is set in .env.
|
|
90
|
+
Clients must authenticate with their identity key to establish a WebSocket connection.
|
|
91
|
+
________________________________________
|
|
92
|
+
### Testing
|
|
93
|
+
To run tests:
|
|
94
|
+
```bash
|
|
95
|
+
npm test
|
|
96
|
+
```
|
|
97
|
+
This includes unit tests and integration tests for HTTP and WebSocket message delivery.
|
|
98
|
+
________________________________________
|
|
99
|
+
### Docker Usage
|
|
100
|
+
Use Docker only if you're running a local test instance:
|
|
101
|
+
```bash
|
|
102
|
+
docker compose up -- build
|
|
103
|
+
```
|
|
104
|
+
- Web server runs on port 3002
|
|
105
|
+
- Database runs on port 3001
|
|
106
|
+
- PHPMyAdmin (for SQL browsing) runs on port 3003
|
|
107
|
+
________________________________________
|
|
108
|
+
### Deployment on Google Cloud Run
|
|
109
|
+
MessageBox can also be containerized and deployed on Google Cloud Run or any similar service. See DEPLOYING.md in backend/ for overlay-specific LARS deployment instructions.
|
|
110
|
+
________________________________________
|
|
111
|
+
### Related Projects
|
|
112
|
+
- [MessageBoxClient](https://github.com/bitcoin-sv/p2p)
|
|
113
|
+
- [WalletClient](https://github.com/bitcoin-sv)
|
|
114
|
+
- [Auth Middleware](https://www.npmjs.com/package/@bsv/auth-express-middleware)
|
|
115
|
+
________________________________________
|
|
116
|
+
📄 License
|
|
117
|
+
The MessageBox Server is licensed under the [Open BSV License](https://www.bsvlicense.org/).
|
|
118
|
+
________________________________________
|
|
119
|
+
|
|
120
|
+
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# ---- Build stage ----
|
|
2
|
+
FROM node:20-alpine AS builder
|
|
3
|
+
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
|
|
6
|
+
# Native deps (better-sqlite3) compile from source on Alpine (musl, no prebuilt
|
|
7
|
+
# binaries) — needs python3/make/g++.
|
|
8
|
+
RUN apk add --no-cache python3 make g++
|
|
9
|
+
|
|
10
|
+
# Copy package files first for better layer caching
|
|
11
|
+
COPY package*.json ./
|
|
12
|
+
COPY tsconfig*.json ./
|
|
13
|
+
COPY knexfile.ts ./
|
|
14
|
+
|
|
15
|
+
# Install all dependencies (including dev deps for build)
|
|
16
|
+
RUN npm install
|
|
17
|
+
|
|
18
|
+
# Install global tools (optional, depends on how you're running knex)
|
|
19
|
+
RUN npm install -g knex typescript
|
|
20
|
+
|
|
21
|
+
# Copy source code required for compilation
|
|
22
|
+
COPY src ./src
|
|
23
|
+
|
|
24
|
+
# Build the TypeScript project
|
|
25
|
+
RUN npm run build
|
|
26
|
+
|
|
27
|
+
# Copy compiled knexfile.js to /app root (where imports like '../../knexfile.js' expect it)
|
|
28
|
+
RUN cp out/knexfile.js ./knexfile.js
|
|
29
|
+
|
|
30
|
+
# ---- Production stage ----
|
|
31
|
+
FROM node:20-alpine
|
|
32
|
+
|
|
33
|
+
# Ensure all OS packages are up to date (patch CVEs in base image) and install nginx
|
|
34
|
+
RUN apk upgrade --no-cache && \
|
|
35
|
+
apk add --no-cache nginx && \
|
|
36
|
+
chown -R nginx:www-data /var/lib/nginx
|
|
37
|
+
|
|
38
|
+
WORKDIR /app
|
|
39
|
+
|
|
40
|
+
# Copy package files and install production deps only.
|
|
41
|
+
# better-sqlite3 compiles from source on Alpine; add the toolchain just for the
|
|
42
|
+
# install, then remove it in the same layer to keep the image slim.
|
|
43
|
+
COPY --chown=root:root --chmod=0444 package*.json ./
|
|
44
|
+
RUN apk add --no-cache --virtual .build-deps python3 make g++ \
|
|
45
|
+
&& npm ci --omit=dev \
|
|
46
|
+
&& apk del .build-deps \
|
|
47
|
+
&& rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
|
|
48
|
+
|
|
49
|
+
# Copy built output from builder
|
|
50
|
+
COPY --from=builder --chown=root:root --chmod=0555 /app/out ./out
|
|
51
|
+
COPY --from=builder --chown=root:root --chmod=0444 /app/knexfile.js ./knexfile.js
|
|
52
|
+
|
|
53
|
+
# Copy nginx config
|
|
54
|
+
COPY ./nginx.conf /etc/nginx/nginx.conf
|
|
55
|
+
|
|
56
|
+
# Expose the API port
|
|
57
|
+
EXPOSE 8080
|
|
58
|
+
|
|
59
|
+
USER node
|
|
60
|
+
|
|
61
|
+
# Start the app with the OpenTelemetry bootstrap preloaded (ESM --import) so
|
|
62
|
+
# auto-instrumentation patches modules before they are imported.
|
|
63
|
+
CMD [ "node", "--import", "./out/src/telemetry.js", "out/src/index.js" ]
|