@bopen-io/messagebox-server 1.1.5 → 1.2.1

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.
Files changed (113) hide show
  1. package/.dockerignore +11 -0
  2. package/.env.example +11 -0
  3. package/.eslintignore +2 -0
  4. package/.gcloudignore +17 -0
  5. package/.gitattributes +2 -0
  6. package/.github/workflows/build-and-push.yml +51 -0
  7. package/.github/workflows/deploy.yaml.example +64 -0
  8. package/.github/workflows/image.yaml +66 -0
  9. package/.vscode/launch.json +67 -0
  10. package/AGENTS.md +92 -0
  11. package/BASELINE.md +55 -0
  12. package/DEPLOYING.md +120 -0
  13. package/Dockerfile +63 -0
  14. package/docker-compose.yml +64 -0
  15. package/jest.config.integration.ts +26 -0
  16. package/jest.config.mjs +42 -0
  17. package/jest.config.ts +35 -0
  18. package/jest.setup.mjs +18 -0
  19. package/nginx.conf +36 -0
  20. package/package.json +68 -52
  21. package/scripts/build.js +19 -0
  22. package/scripts/mkenv.sh +31 -0
  23. package/scripts/start.sh +16 -0
  24. package/src/__tests/compose.test.ts +30 -0
  25. package/src/app.ts +210 -0
  26. package/src/compose.ts +286 -0
  27. package/src/config/firebase.ts +183 -0
  28. package/src/context.ts +49 -0
  29. package/src/index.ts +375 -0
  30. package/src/routes/__tests/acknowledgeMessage.test.ts +158 -0
  31. package/src/routes/__tests/listMessages.test.ts +240 -0
  32. package/src/routes/__tests/sendMessage.test.ts +362 -0
  33. package/src/routes/acknowledgeMessage.ts +153 -0
  34. package/src/routes/index.ts +17 -0
  35. package/src/routes/listDevices.ts +80 -0
  36. package/src/routes/listMessages.ts +195 -0
  37. package/src/routes/permissions/getPermission.ts +152 -0
  38. package/src/routes/permissions/getQuote.ts +192 -0
  39. package/src/routes/permissions/index.ts +12 -0
  40. package/src/routes/permissions/listPermissions.ts +202 -0
  41. package/src/routes/permissions/setPermission.ts +155 -0
  42. package/src/routes/registerDevice.ts +155 -0
  43. package/src/routes/sendMessage.ts +531 -0
  44. package/src/runtimeDeps.ts +29 -0
  45. package/src/swagger.ts +54 -0
  46. package/src/telemetry.ts +158 -0
  47. package/src/types/messagePermissions.ts +18 -0
  48. package/src/types/mock-knex.d.ts +18 -0
  49. package/src/types/notifications.ts +27 -0
  50. package/src/utils/logger.ts +92 -0
  51. package/src/utils/messagePermissions.ts +148 -0
  52. package/src/utils/sendFCMNotification.ts +143 -0
  53. package/tsconfig.json +36 -0
  54. package/tsconfig.types.json +11 -0
  55. package/out/knexfile.js +0 -25
  56. package/out/knexfile.js.map +0 -1
  57. package/out/src/app.js +0 -160
  58. package/out/src/app.js.map +0 -1
  59. package/out/src/config/firebase.js +0 -150
  60. package/out/src/config/firebase.js.map +0 -1
  61. package/out/src/index.js +0 -295
  62. package/out/src/index.js.map +0 -1
  63. package/out/src/migrations/2022-12-28-001-initial-migration.js +0 -28
  64. package/out/src/migrations/2022-12-28-001-initial-migration.js.map +0 -1
  65. package/out/src/migrations/2023-01-17-messages-update.js +0 -11
  66. package/out/src/migrations/2023-01-17-messages-update.js.map +0 -1
  67. package/out/src/migrations/2024-03-05-001-messageID-upgrade.js +0 -21
  68. package/out/src/migrations/2024-03-05-001-messageID-upgrade.js.map +0 -1
  69. package/out/src/migrations/2025-01-31-001-notification-permissions.js +0 -59
  70. package/out/src/migrations/2025-01-31-001-notification-permissions.js.map +0 -1
  71. package/out/src/migrations/2025-01-31-002-device-registrations.js +0 -24
  72. package/out/src/migrations/2025-01-31-002-device-registrations.js.map +0 -1
  73. package/out/src/routes/__tests/acknowledgeMessage.test.js +0 -129
  74. package/out/src/routes/__tests/acknowledgeMessage.test.js.map +0 -1
  75. package/out/src/routes/__tests/listMessages.test.js +0 -211
  76. package/out/src/routes/__tests/listMessages.test.js.map +0 -1
  77. package/out/src/routes/__tests/sendMessage.test.js +0 -307
  78. package/out/src/routes/__tests/sendMessage.test.js.map +0 -1
  79. package/out/src/routes/acknowledgeMessage.js +0 -144
  80. package/out/src/routes/acknowledgeMessage.js.map +0 -1
  81. package/out/src/routes/index.js +0 -17
  82. package/out/src/routes/index.js.map +0 -1
  83. package/out/src/routes/listDevices.js +0 -74
  84. package/out/src/routes/listDevices.js.map +0 -1
  85. package/out/src/routes/listMessages.js +0 -186
  86. package/out/src/routes/listMessages.js.map +0 -1
  87. package/out/src/routes/permissions/getPermission.js +0 -149
  88. package/out/src/routes/permissions/getPermission.js.map +0 -1
  89. package/out/src/routes/permissions/getQuote.js +0 -165
  90. package/out/src/routes/permissions/getQuote.js.map +0 -1
  91. package/out/src/routes/permissions/index.js +0 -12
  92. package/out/src/routes/permissions/index.js.map +0 -1
  93. package/out/src/routes/permissions/listPermissions.js +0 -190
  94. package/out/src/routes/permissions/listPermissions.js.map +0 -1
  95. package/out/src/routes/permissions/setPermission.js +0 -137
  96. package/out/src/routes/permissions/setPermission.js.map +0 -1
  97. package/out/src/routes/registerDevice.js +0 -150
  98. package/out/src/routes/registerDevice.js.map +0 -1
  99. package/out/src/routes/sendMessage.js +0 -451
  100. package/out/src/routes/sendMessage.js.map +0 -1
  101. package/out/src/swagger.js +0 -49
  102. package/out/src/swagger.js.map +0 -1
  103. package/out/src/types/messagePermissions.js +0 -2
  104. package/out/src/types/messagePermissions.js.map +0 -1
  105. package/out/src/types/notifications.js +0 -2
  106. package/out/src/types/notifications.js.map +0 -1
  107. package/out/src/utils/logger.js +0 -24
  108. package/out/src/utils/logger.js.map +0 -1
  109. package/out/src/utils/messagePermissions.js +0 -126
  110. package/out/src/utils/messagePermissions.js.map +0 -1
  111. package/out/src/utils/sendFCMNotification.js +0 -121
  112. package/out/src/utils/sendFCMNotification.js.map +0 -1
  113. package/out/tsconfig.tsbuildinfo +0 -1
package/.dockerignore ADDED
@@ -0,0 +1,11 @@
1
+ .git
2
+ node_modules
3
+ out
4
+ dist
5
+ build
6
+ coverage
7
+ logs
8
+ *.log
9
+ .vscode
10
+ .DS_Store
11
+ .env
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
@@ -0,0 +1,2 @@
1
+ node_modules
2
+ dist
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,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -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" ]