@bopen-io/messagebox-server 1.1.5

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 (69) hide show
  1. package/README.md +372 -0
  2. package/knexfile.d.ts +5 -0
  3. package/knexfile.ts +29 -0
  4. package/out/knexfile.js +25 -0
  5. package/out/knexfile.js.map +1 -0
  6. package/out/src/app.js +160 -0
  7. package/out/src/app.js.map +1 -0
  8. package/out/src/config/firebase.js +150 -0
  9. package/out/src/config/firebase.js.map +1 -0
  10. package/out/src/index.js +295 -0
  11. package/out/src/index.js.map +1 -0
  12. package/out/src/migrations/2022-12-28-001-initial-migration.js +28 -0
  13. package/out/src/migrations/2022-12-28-001-initial-migration.js.map +1 -0
  14. package/out/src/migrations/2023-01-17-messages-update.js +11 -0
  15. package/out/src/migrations/2023-01-17-messages-update.js.map +1 -0
  16. package/out/src/migrations/2024-03-05-001-messageID-upgrade.js +21 -0
  17. package/out/src/migrations/2024-03-05-001-messageID-upgrade.js.map +1 -0
  18. package/out/src/migrations/2025-01-31-001-notification-permissions.js +59 -0
  19. package/out/src/migrations/2025-01-31-001-notification-permissions.js.map +1 -0
  20. package/out/src/migrations/2025-01-31-002-device-registrations.js +24 -0
  21. package/out/src/migrations/2025-01-31-002-device-registrations.js.map +1 -0
  22. package/out/src/routes/__tests/acknowledgeMessage.test.js +129 -0
  23. package/out/src/routes/__tests/acknowledgeMessage.test.js.map +1 -0
  24. package/out/src/routes/__tests/listMessages.test.js +211 -0
  25. package/out/src/routes/__tests/listMessages.test.js.map +1 -0
  26. package/out/src/routes/__tests/sendMessage.test.js +307 -0
  27. package/out/src/routes/__tests/sendMessage.test.js.map +1 -0
  28. package/out/src/routes/acknowledgeMessage.js +144 -0
  29. package/out/src/routes/acknowledgeMessage.js.map +1 -0
  30. package/out/src/routes/index.js +17 -0
  31. package/out/src/routes/index.js.map +1 -0
  32. package/out/src/routes/listDevices.js +74 -0
  33. package/out/src/routes/listDevices.js.map +1 -0
  34. package/out/src/routes/listMessages.js +186 -0
  35. package/out/src/routes/listMessages.js.map +1 -0
  36. package/out/src/routes/permissions/getPermission.js +149 -0
  37. package/out/src/routes/permissions/getPermission.js.map +1 -0
  38. package/out/src/routes/permissions/getQuote.js +165 -0
  39. package/out/src/routes/permissions/getQuote.js.map +1 -0
  40. package/out/src/routes/permissions/index.js +12 -0
  41. package/out/src/routes/permissions/index.js.map +1 -0
  42. package/out/src/routes/permissions/listPermissions.js +190 -0
  43. package/out/src/routes/permissions/listPermissions.js.map +1 -0
  44. package/out/src/routes/permissions/setPermission.js +137 -0
  45. package/out/src/routes/permissions/setPermission.js.map +1 -0
  46. package/out/src/routes/registerDevice.js +150 -0
  47. package/out/src/routes/registerDevice.js.map +1 -0
  48. package/out/src/routes/sendMessage.js +451 -0
  49. package/out/src/routes/sendMessage.js.map +1 -0
  50. package/out/src/swagger.js +49 -0
  51. package/out/src/swagger.js.map +1 -0
  52. package/out/src/types/messagePermissions.js +2 -0
  53. package/out/src/types/messagePermissions.js.map +1 -0
  54. package/out/src/types/notifications.js +2 -0
  55. package/out/src/types/notifications.js.map +1 -0
  56. package/out/src/utils/logger.js +24 -0
  57. package/out/src/utils/logger.js.map +1 -0
  58. package/out/src/utils/messagePermissions.js +126 -0
  59. package/out/src/utils/messagePermissions.js.map +1 -0
  60. package/out/src/utils/sendFCMNotification.js +121 -0
  61. package/out/src/utils/sendFCMNotification.js.map +1 -0
  62. package/out/tsconfig.tsbuildinfo +1 -0
  63. package/package.json +88 -0
  64. package/src/migrations/2022-12-28-001-initial-migration.ts +31 -0
  65. package/src/migrations/2023-01-17-messages-update.ts +13 -0
  66. package/src/migrations/2024-03-05-001-messageID-upgrade.ts +25 -0
  67. package/src/migrations/2025-01-31-001-notification-permissions.ts +68 -0
  68. package/src/migrations/2025-01-31-002-device-registrations.ts +28 -0
  69. package/src/templates/documentation.ejs +62 -0
package/README.md ADDED
@@ -0,0 +1,372 @@
1
+ # Message Box Server
2
+
3
+ A secure, peer-to-peer message routing server designed for the Bitcoin SV ecosystem. Supports both HTTP and WebSocket message transport, encrypted payloads, identity-based routing, and overlay advertisement via SHIP.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Overview](#1-overview)
8
+ 2. [Concepts](#2-concepts)
9
+ 3. [Environment Variables](#3-environment-variables)
10
+ 4. [Quick Start](#4-quick-start)
11
+ 5. [Examples](#5-examples)
12
+ 6. [API Reference](#6-api-reference)
13
+ - [POST /sendMessage](#post-sendmessage)
14
+ - [POST /listMessages](#post-listmessages)
15
+ - [POST /acknowledgeMessage](#post-acknowledgemessage)
16
+ 7. [WebSocket Support](#7-websocket-support)
17
+ 8. [Authentication](#8-authentication)
18
+ 9. [Scripts](#9-scripts)
19
+ 10. [Deploying](#10-deploying)
20
+ 11. [License](#11-license)
21
+
22
+ ## 1. Overview
23
+
24
+ MessageBox is a peer-to-peer messaging API that enables secure, encrypted, and authenticated communication between users on the MetaNet. This is primarily achieved through a message-box architecture combined with optional overlay routing and real-time WebSocket transport.
25
+
26
+ When a user sends a message, they must specify the messageBox type and the intended recipient (an identity key). This design allows for protocol-specific messageBox types to be defined at higher application layers, while maintaining clear separation of messages by type and recipient. Each message is routed into a box associated with a specific recipient and use case.
27
+
28
+ Security is a critical aspect of MessageBox. It relies on [AuthExpress middleware](https://github.com/bitcoin-sv/auth-express-middleware) to ensure that only the recipient can access and acknowledge their own messages. Encrypted payloads are supported automatically following [BRC-2](https://github.com/bitcoin-sv/BRCs/blob/master/wallet/0002.md), using secure symmetric encryption between authenticated peers.
29
+
30
+ MessageBox also supports [@bsv/authsocket](https://www.npmjs.com/package/@bsv/authsocket) for real-time authenticated WebSocket communication. This enables clients to receive messages instantly and interact with rooms associated with their identity key and chosen messageBox.
31
+
32
+ To interact with MessageBox, use [MessageBoxClient](https://github.com/bitcoin-sv/p2p), the client-side library designed to handle authentication, encryption, WebSocket communication, and overlay resolution.
33
+
34
+ ## 2. Concepts
35
+ - **Identity Key:** All messages are addressed to an identity key (a public key)
36
+ - **MessageBox:** A named message stream associated with an identity key (e.g., payment_inbox)
37
+ - **Encrypted Payloads:** Messages can be AES-encrypted and include metadata
38
+ - **Live Messaging:** Clients can join WebSocket rooms and receive messages in real-time
39
+ - **Acknowledgment:** Messages must be acknowledged to be removed from the database
40
+ ________________________________________
41
+
42
+ ## 3. Environment Variables
43
+ **Variables**
44
+
45
+ NODE_ENV - Set to development, staging, or production
46
+
47
+ PORT - Port for the HTTP server (default: 8080 or 3000)
48
+
49
+ ROUTING_PREFIX - (Optional) Prefix for all HTTP and WebSocket routes (e.g., /api)
50
+
51
+ HOSTING_DOMAIN - (Optional) Full domain where this server is hosted (used in overlay metadata)
52
+
53
+ SERVER_PRIVATE_KEY - Required. 256-bit hex private key used for identity, signing, and authentication
54
+
55
+ WALLET_STORAGE_URL - URL of a wallet-storage service that stores key derivation metadata
56
+
57
+ NETWORK - Target network chain (e.g., main, test, or regtest)
58
+
59
+ KNEX_DB_CONNECTION - (Optional) JSON-formatted connection string for MySQL/Knex (if not using default)
60
+
61
+ ENABLE_WEBSOCKETS - Set to 'true' to enable real-time messaging over WebSocket
62
+
63
+ LOGGING_ENABLED - Set to 'true' to enable verbose debug logging in any environment
64
+
65
+ MIGRATE_KEY - (Optional) Key used to authorize protected migration operations, if required
66
+
67
+ ________________________________________
68
+
69
+ ## 4. Quick Start
70
+
71
+ To run the MessageBox Server locally or in a hosted environment, follow the steps below.
72
+
73
+ 1. **Clone the Repository**
74
+ ```bash
75
+ git clone https://github.com/bitcoin-sv/messagebox-server.git
76
+ cd messagebox-server
77
+ ```
78
+
79
+ 2. **Configure Environment Variables**
80
+ Create a .env file based on the variables listed in the Environment Variables section:
81
+
82
+ ```bash
83
+ cp .env.example .env
84
+ ```
85
+
86
+ Then fill in or update the necessary fields in .env, including:
87
+
88
+ SERVER_PRIVATE_KEY – your root private key for identity/auth
89
+
90
+ WALLET_STORAGE_URL – points to a wallet-storage instance
91
+
92
+ (Optional) KNEX_DB_CONNECTION – if you're not using the default MySQL config
93
+
94
+ For local development, use:
95
+
96
+ ```bash
97
+ .env
98
+ NODE_ENV=development
99
+ BSV_NETWORK=local
100
+ ```
101
+
102
+ 3. **Install Dependencies**
103
+ ```bash
104
+ npm install
105
+ ```
106
+
107
+ 4. **Start the Server**
108
+
109
+ ```bash
110
+ npm run dev
111
+ ```
112
+ **Note:**
113
+ MessageBox Server requires a MySQL database for storing messages.
114
+ See [Deploying](#10-deploying) for instructions on setting up the required database locally or in production environments.
115
+
116
+ This launches the Express-based MessageBox Server on the configured port (default: 8080 or 3000 in production). WebSocket support will be enabled if ENABLE_WEBSOCKETS=true in your environment.
117
+
118
+ You can customize the HTTP port using the PORT variable in .env.
119
+
120
+ You're now ready to send and receive messages using the MessageBoxClient, test endpoints, and participate in the overlay network.
121
+
122
+ ________________________________________
123
+
124
+ ## 5. Examples
125
+
126
+ This section provides quick examples for sending, listing, and acknowledging messages using the MessageBoxClient library.
127
+
128
+ 1. **Sending a Message**
129
+ ```ts
130
+ import { WalletClient } from '@bsv/sdk'
131
+ import { MessageBoxClient } from '@bsv/p2p'
132
+
133
+ const wallet = new WalletClient()
134
+ const mb = new MessageBoxClient({
135
+ walletClient: wallet,
136
+ host: 'http://localhost:8080' // your MessageBoxServer instance
137
+ })
138
+
139
+ await mb.sendMessage({
140
+ recipient: '028d37b941208cd6b8a4c28288eda5f2f16c2b3ab0fcb6d13c18b47fe37b971fc1',
141
+ messageBox: 'demo_inbox',
142
+ body: { text: 'Hello there!' }
143
+ })
144
+ ```
145
+
146
+ 2. **Listening for Live Messages (WebSocket)**
147
+ ```ts
148
+ await mb.initializeConnection()
149
+
150
+ await mb.listenForLiveMessages({
151
+ messageBox: 'demo_inbox',
152
+ onMessage: (msg) => {
153
+ console.log('New Message:', msg)
154
+ }
155
+ })
156
+ ```
157
+
158
+ 3. **Listing Messages via HTTP**
159
+ ```ts
160
+ const messages = await mb.listMessages({
161
+ messageBox: 'demo_inbox'
162
+ })
163
+
164
+ console.log('All Messages:', messages)
165
+ ```
166
+
167
+ 4. **Acknowledging Messages (Marking as Read)**
168
+ ```ts
169
+ const toAcknowledge = messages.map(m => m.messageId.toString())
170
+
171
+ await mb.acknowledgeMessage({
172
+ messageIds: toAcknowledge
173
+ })
174
+ ```
175
+
176
+ 5. **Sending a Live Message with Fallback**
177
+ ```ts
178
+ await mb.sendLiveMessage({
179
+ recipient: '028d37b941208cd6b8a4c28288eda5f2f16c2b3ab0fcb6d13c18b47fe37b971fc1',
180
+ messageBox: 'demo_inbox',
181
+ body: 'This will try WebSocket first, and fallback to HTTP if needed.'
182
+ })
183
+ ```
184
+
185
+ ________________________________________
186
+
187
+ ## 6. API Reference
188
+ The MessageBox Server exposes a small set of authenticated HTTP endpoints to support secure, store-and-forward messaging. All routes require identity-based authentication using @bsv/auth-express-middleware.
189
+
190
+ ### POST /sendMessage
191
+ Send a message to a specific recipient’s message box.
192
+
193
+ **Request Body**
194
+ ```json
195
+ {
196
+ "message": {
197
+ "recipient": "IDENTITY_PUBLIC_KEY",
198
+ "messageBox": "payment_inbox",
199
+ "messageId": "abc123",
200
+ "body": "{\"amount\":10000}"
201
+ }
202
+ }
203
+ ```
204
+
205
+ **Response**
206
+ ```json
207
+ {
208
+ "status": "success",
209
+ "messageId": "abc123",
210
+ "message": "Your message has been sent to IDENTITY_PUBLIC_KEY"
211
+ }
212
+ ```
213
+
214
+ Messages are persisted in the recipient’s messageBox.
215
+
216
+ messageId must be globally unique (can be derived using HMAC).
217
+
218
+ Duplicate messageIds will be ignored.
219
+
220
+ ### POST /listMessages
221
+ List all messages from a given messageBox owned by the authenticated identity.
222
+
223
+ **Request Body**
224
+ ```json
225
+ {
226
+ "messageBox": "payment_inbox"
227
+ }
228
+ ```
229
+
230
+ **Response**
231
+ ```json
232
+ {
233
+ "status": "success",
234
+ "messages": [
235
+ {
236
+ "messageId": "abc123",
237
+ "body": "{\"amount\":10000}",
238
+ "sender": "SENDER_PUBLIC_KEY",
239
+ "created_at": "2024-12-01T12:00:00Z",
240
+ "updated_at": "2024-12-01T12:01:00Z"
241
+ }
242
+ ]
243
+ }
244
+ ```
245
+
246
+ Message bodies will be returned as strings (plain or encrypted).
247
+
248
+ Empty arrays are returned if no messages exist or the box is unregistered.
249
+
250
+ ### POST /acknowledgeMessage
251
+ Permanently delete one or more messages after they have been processed.
252
+
253
+ **Request Body**
254
+ ```json
255
+ {
256
+ "messageIds": ["abc123", "def456"]
257
+ }
258
+ ```
259
+
260
+ **Response**
261
+ ```json
262
+ {
263
+ "status": "success"
264
+ }
265
+ ```
266
+
267
+ This action cannot be undone.
268
+
269
+ Only messages owned by the authenticated identity can be acknowledged.
270
+
271
+ Note: All requests must include automatically signed and verified headers following [BRC-103](https://github.com/bitcoin-sv/BRCs/blob/master/peer-to-peer/0103.md) authentication.
272
+ Mutual authentication is handled transparently by [@bsv/auth-express-middleware](https://www.npmjs.com/package/@bsv/auth-express-middleware).
273
+
274
+ ________________________________________
275
+
276
+ ## 7. WebSocket Support
277
+ The MessageBox Server supports real-time messaging over WebSocket using @bsv/authsocket. This allows clients to send and receive messages instantly without polling.
278
+
279
+ **Connection**
280
+ Clients should connect to the same host and port used by the HTTP server (e.g., ws://localhost:8080) and must authenticate using their identity key.
281
+
282
+ **Authentication**
283
+ There are two ways to authenticate:
284
+
285
+ During initial connection: Send the identityKey as part of the connection handshake.
286
+
287
+ After connecting: Emit an authenticated event with { identityKey }.
288
+
289
+ Once authenticated, the server emits authenticationSuccess. If the key is missing or invalid, authenticationFailed is returned.
290
+
291
+ **Room Format**
292
+ Each messageBox uses a room in the format:
293
+
294
+ ```bash
295
+ {identityKey}-{messageBox}
296
+ ```
297
+ For example:
298
+ 028d37b94120...-payment_inbox
299
+
300
+ **Events**
301
+
302
+ authenticated - Authenticate using an identity key
303
+ joinRoom - Subscribe to a specific messageBox room
304
+ sendMessage - Send a message to a room (triggers DB storage + broadcast)
305
+ sendMessageAck-ROOM - Acknowledgment that the message was received by the server
306
+ sendMessage-ROOM - Broadcasted message to all listeners in the room
307
+ leaveRoom - Unsubscribe from a room
308
+
309
+ **Example WebSocket Usage (Client)**
310
+ ```ts
311
+ import { io } from 'socket.io-client'
312
+
313
+ const socket = io('ws://localhost:8080')
314
+
315
+ // Step 1: Authenticate after connection
316
+ socket.emit('authenticated', { identityKey })
317
+
318
+ // Step 2: Join a messageBox room
319
+ socket.emit('joinRoom', '028d...-payment_inbox')
320
+
321
+ // Step 3: Send a message
322
+ socket.emit('sendMessage', {
323
+ roomId: '028d...-payment_inbox',
324
+ message: {
325
+ messageId: 'abc123',
326
+ recipient: '028d...',
327
+ body: JSON.stringify({ hello: 'world' })
328
+ }
329
+ })
330
+
331
+ // Step 4: Listen for acknowledgment and broadcast
332
+ socket.on('sendMessageAck-028d...-payment_inbox', (ack) => {
333
+ console.log('Message acknowledged:', ack)
334
+ })
335
+
336
+ socket.on('sendMessage-028d...-payment_inbox', (msg) => {
337
+ console.log('New message received:', msg)
338
+ })
339
+ ```
340
+
341
+ **Notes**
342
+ Messages sent via WebSocket are also persisted in the database.
343
+
344
+ If a room is not joined or the recipient isn't online, delivery is deferred until the recipient polls via HTTP.
345
+
346
+ If ENABLE_WEBSOCKETS is not set to 'true', this functionality is disabled.
347
+
348
+ ________________________________________
349
+ ## 8. Authentication
350
+ All HTTP and WebSocket communications use full mutual authentication based on [BRC-103](https://github.com/bitcoin-sv/BRCs/blob/master/peer-to-peer/0103.md).
351
+ - HTTP requests are authenticated using [@bsv/auth-express-middleware](https://www.npmjs.com/package/@bsv/auth-express-middleware), with automatically signed and verified headers.
352
+ - WebSocket connections are authenticated using [@bsv/authsocket](https://www.npmjs.com/package/@bsv/authsocket), signing the WebSocket handshake and room interactions.
353
+
354
+ Clients authenticate automatically when using the [MessageBoxClient](https://github.com/bitcoin-sv/p2p) library. Manual integrations must follow BRC-103 signing conventions.
355
+
356
+ ________________________________________
357
+
358
+ ## 9. Scripts
359
+ ```bash
360
+ npm run dev # Start with hot reloading
361
+ npm run start # Start in production
362
+ npm run test # Run all tests
363
+ npm run build # Compile documentation
364
+ ```
365
+ ________________________________________
366
+
367
+ ## 10. Deploying
368
+ See [DEPLOYING.md](./DEPLOYING.md) for tips.
369
+ ________________________________________
370
+ ## 11. License
371
+ This project is released under the [Open BSV License](https://www.bsvlicense.org/).
372
+
package/knexfile.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { Knex } from 'knex'
2
+ declare const knexConfig: {
3
+ [key: string]: Knex.Config
4
+ }
5
+ export default knexConfig
package/knexfile.ts ADDED
@@ -0,0 +1,29 @@
1
+ import dotenv from 'dotenv'
2
+ import type { Knex } from 'knex'
3
+ dotenv.config()
4
+
5
+ const connectionConfig = process.env.KNEX_DB_CONNECTION != null && process.env.KNEX_DB_CONNECTION.trim() !== ''
6
+ ? JSON.parse(process.env.KNEX_DB_CONNECTION)
7
+ : undefined
8
+
9
+ const config: Knex.Config = {
10
+ client: process.env.KNEX_DB_CLIENT ?? 'mysql2',
11
+ connection: connectionConfig,
12
+ useNullAsDefault: true,
13
+ migrations: {
14
+ directory: './out/src/migrations'
15
+ },
16
+ pool: {
17
+ min: 0,
18
+ max: 7,
19
+ idleTimeoutMillis: 15000
20
+ }
21
+ }
22
+
23
+ const knexfile: { [key: string]: Knex.Config } = {
24
+ development: config,
25
+ staging: config,
26
+ production: config
27
+ }
28
+
29
+ export default knexfile
@@ -0,0 +1,25 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+ const connectionConfig = process.env.KNEX_DB_CONNECTION != null && process.env.KNEX_DB_CONNECTION.trim() !== ''
4
+ ? JSON.parse(process.env.KNEX_DB_CONNECTION)
5
+ : undefined;
6
+ const config = {
7
+ client: process.env.KNEX_DB_CLIENT ?? 'mysql2',
8
+ connection: connectionConfig,
9
+ useNullAsDefault: true,
10
+ migrations: {
11
+ directory: './out/src/migrations'
12
+ },
13
+ pool: {
14
+ min: 0,
15
+ max: 7,
16
+ idleTimeoutMillis: 15000
17
+ }
18
+ };
19
+ const knexfile = {
20
+ development: config,
21
+ staging: config,
22
+ production: config
23
+ };
24
+ export default knexfile;
25
+ //# sourceMappingURL=knexfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knexfile.js","sourceRoot":"","sources":["../knexfile.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,MAAM,CAAC,MAAM,EAAE,CAAA;AAEf,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE;IAC7G,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC5C,CAAC,CAAC,SAAS,CAAA;AAEb,MAAM,MAAM,GAAgB;IAC1B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,QAAQ;IAC9C,UAAU,EAAE,gBAAgB;IAC5B,gBAAgB,EAAE,IAAI;IACtB,UAAU,EAAE;QACV,SAAS,EAAE,sBAAsB;KAClC;IACD,IAAI,EAAE;QACJ,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,CAAC;QACN,iBAAiB,EAAE,KAAK;KACzB;CACF,CAAA;AAED,MAAM,QAAQ,GAAmC;IAC/C,WAAW,EAAE,MAAM;IACnB,OAAO,EAAE,MAAM;IACf,UAAU,EAAE,MAAM;CACnB,CAAA;AAED,eAAe,QAAQ,CAAA"}
package/out/src/app.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @file app.ts
3
+ * @description
4
+ * Initializes the MessageBoxServer Express app.
5
+ *
6
+ * Responsibilities:
7
+ * - Parses environment variables and loads config
8
+ * - Sets up Knex for DB access
9
+ * - Initializes WalletClient from the BSV SDK
10
+ * - Mounts Express routes (pre-auth and post-auth)
11
+ * - Applies auth middleware using wallet identity
12
+ *
13
+ * This file exports:
14
+ * - `app`: the configured Express instance
15
+ * - `walletReady`: a promise that resolves once the wallet is ready
16
+ * - `getWallet()`: async accessor for the WalletClient
17
+ * - `useRoutes()`: middleware + route initialization
18
+ * - `appReady`: promise that completes once all setup is done
19
+ */
20
+ import * as dotenv from 'dotenv';
21
+ import express from 'express';
22
+ import bodyParser from 'body-parser';
23
+ import { preAuth, postAuth } from './routes/index.js';
24
+ import { Logger } from './utils/logger.js';
25
+ import sendMessageRoute from './routes/sendMessage.js';
26
+ import { Setup } from '@bsv/wallet-toolbox';
27
+ import knexLib from 'knex';
28
+ import knexConfig from '../knexfile.js';
29
+ import { createAuthMiddleware } from '@bsv/auth-express-middleware';
30
+ import { createPaymentMiddleware } from '@bsv/payment-express-middleware';
31
+ import { setupSwagger } from './swagger.js';
32
+ import * as crypto from 'crypto';
33
+ global.self = { crypto };
34
+ dotenv.config();
35
+ // Create the Express app instance
36
+ export const app = express();
37
+ // Load environment variables
38
+ const { NODE_ENV = 'development', ROUTING_PREFIX = '', SERVER_PRIVATE_KEY, WALLET_STORAGE_URL, BSV_NETWORK = 'mainnet' } = process.env;
39
+ // Enable logger in dev mode or if explicitly enabled
40
+ if (NODE_ENV === 'development' || process.env.LOGGING_ENABLED === 'true') {
41
+ Logger.enable();
42
+ }
43
+ /**
44
+ * Knex instance connected based on environment (development, production, or staging).
45
+ */
46
+ export const knex = knexLib.default?.(NODE_ENV === 'production' || NODE_ENV === 'staging'
47
+ ? knexConfig.production
48
+ : knexConfig.development) ?? knexLib(NODE_ENV === 'production' || NODE_ENV === 'staging'
49
+ ? knexConfig.production
50
+ : knexConfig.development);
51
+ // Wallet initialization logic
52
+ let _wallet;
53
+ let _resolveReady;
54
+ export const walletReady = new Promise((resolve) => {
55
+ _resolveReady = resolve;
56
+ });
57
+ /**
58
+ * @function initializeWallet
59
+ * @description Initializes the WalletClient with a root identity key and storage backend.
60
+ *
61
+ * Loads configuration from the environment and connects to the wallet service.
62
+ *
63
+ * @returns {Promise<void>} Resolves when the wallet is initialized.
64
+ * @throws If SERVER_PRIVATE_KEY is missing or invalid.
65
+ */
66
+ export async function initializeWallet() {
67
+ if (SERVER_PRIVATE_KEY == null || SERVER_PRIVATE_KEY.trim() === '') {
68
+ throw new Error('SERVER_PRIVATE_KEY is not defined in environment variables.');
69
+ }
70
+ _wallet = await Setup.createWalletClientNoEnv({
71
+ chain: BSV_NETWORK === 'testnet' ? 'test' : 'main',
72
+ rootKeyHex: SERVER_PRIVATE_KEY,
73
+ storageUrl: WALLET_STORAGE_URL
74
+ });
75
+ _resolveReady();
76
+ }
77
+ /**
78
+ * @function getWallet
79
+ * @description Waits for the WalletClient to be ready and returns the instance.
80
+ *
81
+ * @returns {Promise<WalletInterface>} The initialized wallet client
82
+ * @throws {Error} If called before the wallet is initialized
83
+ */
84
+ export async function getWallet() {
85
+ await walletReady;
86
+ if (_wallet == null) {
87
+ throw new Error('Wallet has not been initialized yet.');
88
+ }
89
+ return _wallet;
90
+ }
91
+ // Run on app startup to prep wallet and activate routes
92
+ export const appReady = (async () => {
93
+ await initializeWallet();
94
+ await useRoutes();
95
+ })();
96
+ /**
97
+ * @function useRoutes
98
+ * @description Registers all routes and middleware on the Express app instance.
99
+ *
100
+ * Steps:
101
+ * - Applies JSON body parser
102
+ * - Enables CORS headers for all routes
103
+ * - Waits for WalletClient to initialize
104
+ * - Adds authentication middleware
105
+ * - Mounts pre-auth and post-auth route handlers
106
+ *
107
+ * @returns {Promise<void>} Once all middleware and routes are mounted
108
+ * @throws If wallet is not available when needed
109
+ */
110
+ export async function useRoutes() {
111
+ // Parse incoming JSON bodies with a high limit
112
+ app.use(bodyParser.json({ limit: '1gb', type: 'application/json' }));
113
+ // CORS setup
114
+ app.use((req, res, next) => {
115
+ res.header('Access-Control-Allow-Origin', '*');
116
+ res.header('Access-Control-Allow-Headers', '*');
117
+ res.header('Access-Control-Allow-Methods', '*');
118
+ res.header('Access-Control-Expose-Headers', '*');
119
+ res.header('Access-Control-Allow-Private-Network', 'true');
120
+ if (req.method === 'OPTIONS') {
121
+ res.sendStatus(200);
122
+ }
123
+ else {
124
+ next();
125
+ }
126
+ });
127
+ // Enable Swagger docs
128
+ setupSwagger(app);
129
+ await walletReady;
130
+ if (_wallet == null) {
131
+ throw new Error('Wallet is not initialized for auth middleware');
132
+ }
133
+ app.use(createAuthMiddleware({
134
+ wallet: _wallet,
135
+ logger: console
136
+ }));
137
+ app.use(createPaymentMiddleware({
138
+ wallet: _wallet,
139
+ calculateRequestPrice: async (req) => {
140
+ if (req.url.includes('/sendMessage')) {
141
+ // TODO: Configure a custom price calculation as needed.
142
+ }
143
+ return 0;
144
+ }
145
+ }));
146
+ // Register pre-authentication routes (no auth required)
147
+ preAuth.forEach((route) => {
148
+ app[route.type](`${String(ROUTING_PREFIX)}${String(route.path)}`, route.func);
149
+ });
150
+ // Register post-authentication routes (requires auth header)
151
+ postAuth.forEach((route) => {
152
+ if (route.path === '/sendMessage') {
153
+ app[route.type](`${ROUTING_PREFIX}${route.path}`, sendMessageRoute.func);
154
+ }
155
+ else {
156
+ app[route.type](`${ROUTING_PREFIX}${route.path}`, route.func);
157
+ }
158
+ });
159
+ }
160
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAChC,OAAO,OAMN,MAAM,SAAS,CAAA;AAChB,OAAO,UAAU,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC1C,OAAO,gBAAgB,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,OAAiB,MAAM,MAAM,CAAA;AACpC,OAAO,UAAU,MAAM,gBAAgB,CAAA;AAEvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAC/B,MAAM,CAAC,IAAY,GAAG,EAAE,MAAM,EAAE,CAAA;AAEjC,MAAM,CAAC,MAAM,EAAE,CAAA;AAEf,kCAAkC;AAClC,MAAM,CAAC,MAAM,GAAG,GAAY,OAAO,EAAE,CAAA;AAErC,6BAA6B;AAC7B,MAAM,EACJ,QAAQ,GAAG,aAAa,EACxB,cAAc,GAAG,EAAE,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,GAAG,SAAS,EACxB,GAAG,OAAO,CAAC,GAAG,CAAA;AAEf,qDAAqD;AACrD,IAAI,QAAQ,KAAK,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;IACzE,MAAM,CAAC,MAAM,EAAE,CAAA;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,IAAI,GAAU,OAAe,CAAC,OAAO,EAAE,CAClD,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,SAAS;IACjD,CAAC,CAAC,UAAU,CAAC,UAAU;IACvB,CAAC,CAAC,UAAU,CAAC,WAAW,CAC3B,IAAK,OAAe,CACnB,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,SAAS;IACjD,CAAC,CAAC,UAAU,CAAC,UAAU;IACvB,CAAC,CAAC,UAAU,CAAC,WAAW,CAC3B,CAAA;AAED,8BAA8B;AAC9B,IAAI,OAAoC,CAAA;AACxC,IAAI,aAAyB,CAAA;AAC7B,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;IACvD,aAAa,GAAG,OAAO,CAAA;AACzB,CAAC,CAAC,CAAA;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,kBAAkB,IAAI,IAAI,IAAI,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAA;IAChF,CAAC;IAED,OAAO,GAAG,MAAM,KAAK,CAAC,uBAAuB,CAAC;QAC5C,KAAK,EAAE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAClD,UAAU,EAAE,kBAAkB;QAC9B,UAAU,EAAE,kBAAkB;KAC/B,CAAC,CAAA;IAEF,aAAa,EAAE,CAAA;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,WAAW,CAAA;IACjB,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAK,IAAI,EAAE;IAClC,MAAM,gBAAgB,EAAE,CAAA;IACxB,MAAM,SAAS,EAAE,CAAA;AACnB,CAAC,CAAC,EAAE,CAAA;AAEJ;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,+CAA+C;IAC/C,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAA;IAEpE,aAAa;IACb,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,GAAG,CAAC,MAAM,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAA;QAC9C,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAA;QAC/C,GAAG,CAAC,MAAM,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAA;QAC/C,GAAG,CAAC,MAAM,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAA;QAChD,GAAG,CAAC,MAAM,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAA;QAE1D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACrB,CAAC;aAAM,CAAC;YACN,IAAI,EAAE,CAAA;QACR,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,sBAAsB;IACtB,YAAY,CAAC,GAAG,CAAC,CAAA;IAEjB,MAAM,WAAW,CAAA;IACjB,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IAED,GAAG,CAAC,GAAG,CACL,oBAAoB,CAAC;QACnB,MAAM,EAAE,OAAO;QACf,MAAM,EAAE,OAAO;KAChB,CAAC,CACH,CAAA;IAED,GAAG,CAAC,GAAG,CACL,uBAAuB,CAAC;QACtB,MAAM,EAAE,OAAO;QACf,qBAAqB,EAAE,KAAK,EAAE,GAAY,EAAE,EAAE;YAC5C,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACrC,wDAAwD;YAC1D,CAAC;YACD,OAAO,CAAC,CAAA;QACV,CAAC;KACF,CAAC,CACH,CAAA;IAED,wDAAwD;IACxD,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACxB,GAAG,CAAC,KAAK,CAAC,IAAyC,CAAC,CAClD,GAAG,MAAM,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAChD,KAAK,CAAC,IAAmF,CAC1F,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACzB,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAClC,GAAG,CAAC,KAAK,CAAC,IAAyC,CAAC,CAClD,GAAG,cAAc,GAAG,KAAK,CAAC,IAAI,EAAE,EAChC,gBAAgB,CAAC,IAAiC,CACnD,CAAA;QACH,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,KAAK,CAAC,IAAyC,CAAC,CAClD,GAAG,cAAc,GAAG,KAAK,CAAC,IAAI,EAAE,EAChC,KAAK,CAAC,IAAsB,CAC7B,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}