@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.
- 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 +68 -52
- 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
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import knexConfig from '../../knexfile.js';
|
|
2
|
-
import * as knexLib from 'knex';
|
|
3
|
-
import { Logger } from '../utils/logger.js';
|
|
4
|
-
// Determine the environment (default to development)
|
|
5
|
-
const { NODE_ENV = 'development' } = process.env;
|
|
6
|
-
/**
|
|
7
|
-
* Knex instance connected based on environment (development, production, or staging).
|
|
8
|
-
*/
|
|
9
|
-
const knex = knexLib.default?.(NODE_ENV === 'production' || NODE_ENV === 'staging'
|
|
10
|
-
? knexConfig.production
|
|
11
|
-
: knexConfig.development) ?? knexLib(NODE_ENV === 'production' || NODE_ENV === 'staging'
|
|
12
|
-
? knexConfig.production
|
|
13
|
-
: knexConfig.development);
|
|
14
|
-
/**
|
|
15
|
-
* @swagger
|
|
16
|
-
* /registerDevice:
|
|
17
|
-
* post:
|
|
18
|
-
* summary: Register device for push notifications
|
|
19
|
-
* description: Register a device's FCM token for receiving push notifications
|
|
20
|
-
* tags:
|
|
21
|
-
* - Device
|
|
22
|
-
* requestBody:
|
|
23
|
-
* required: true
|
|
24
|
-
* content:
|
|
25
|
-
* application/json:
|
|
26
|
-
* schema:
|
|
27
|
-
* type: object
|
|
28
|
-
* required:
|
|
29
|
-
* - fcmToken
|
|
30
|
-
* properties:
|
|
31
|
-
* fcmToken:
|
|
32
|
-
* type: string
|
|
33
|
-
* description: Firebase Cloud Messaging token
|
|
34
|
-
* deviceId:
|
|
35
|
-
* type: string
|
|
36
|
-
* description: Optional device identifier
|
|
37
|
-
* platform:
|
|
38
|
-
* type: string
|
|
39
|
-
* description: Device platform (ios, android, web)
|
|
40
|
-
* enum: [ios, android, web]
|
|
41
|
-
* responses:
|
|
42
|
-
* 200:
|
|
43
|
-
* description: Device registered successfully
|
|
44
|
-
* content:
|
|
45
|
-
* application/json:
|
|
46
|
-
* schema:
|
|
47
|
-
* type: object
|
|
48
|
-
* properties:
|
|
49
|
-
* status:
|
|
50
|
-
* type: string
|
|
51
|
-
* example: success
|
|
52
|
-
* message:
|
|
53
|
-
* type: string
|
|
54
|
-
* example: Device registered successfully
|
|
55
|
-
* deviceId:
|
|
56
|
-
* type: integer
|
|
57
|
-
* description: Database ID of the registered device
|
|
58
|
-
* 400:
|
|
59
|
-
* description: Invalid request parameters
|
|
60
|
-
* 401:
|
|
61
|
-
* description: Authentication required
|
|
62
|
-
* 500:
|
|
63
|
-
* description: Internal server error
|
|
64
|
-
*/
|
|
65
|
-
export default {
|
|
66
|
-
type: 'post',
|
|
67
|
-
path: '/registerDevice',
|
|
68
|
-
func: async (req, res) => {
|
|
69
|
-
try {
|
|
70
|
-
Logger.log('[DEBUG] Processing device registration request');
|
|
71
|
-
// Validate authentication
|
|
72
|
-
const identityKey = req.auth?.identityKey;
|
|
73
|
-
if (identityKey == null) {
|
|
74
|
-
Logger.log('[DEBUG] Authentication required for device registration');
|
|
75
|
-
return res.status(401).json({
|
|
76
|
-
status: 'error',
|
|
77
|
-
code: 'ERR_AUTHENTICATION_REQUIRED',
|
|
78
|
-
description: 'Authentication required.'
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
const { fcmToken, deviceId, platform } = req.body;
|
|
82
|
-
// Validate required fields
|
|
83
|
-
if (fcmToken == null || typeof fcmToken !== 'string' || fcmToken.trim() === '') {
|
|
84
|
-
Logger.log('[DEBUG] Invalid FCM token provided');
|
|
85
|
-
return res.status(400).json({
|
|
86
|
-
status: 'error',
|
|
87
|
-
code: 'ERR_INVALID_FCM_TOKEN',
|
|
88
|
-
description: 'fcmToken is required and must be a non-empty string.'
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
// Validate platform if provided
|
|
92
|
-
const validPlatforms = ['ios', 'android', 'web'];
|
|
93
|
-
if (platform != null && !validPlatforms.includes(platform)) {
|
|
94
|
-
Logger.log('[DEBUG] Invalid platform provided');
|
|
95
|
-
return res.status(400).json({
|
|
96
|
-
status: 'error',
|
|
97
|
-
code: 'ERR_INVALID_PLATFORM',
|
|
98
|
-
description: 'platform must be one of: ios, android, web'
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
try {
|
|
102
|
-
// Insert or update device registration
|
|
103
|
-
const now = new Date();
|
|
104
|
-
const [deviceRegistrationId] = await knex('device_registrations')
|
|
105
|
-
.insert({
|
|
106
|
-
identity_key: identityKey,
|
|
107
|
-
fcm_token: fcmToken.trim(),
|
|
108
|
-
device_id: deviceId?.trim() ?? null,
|
|
109
|
-
platform: platform ?? null,
|
|
110
|
-
created_at: now,
|
|
111
|
-
updated_at: now,
|
|
112
|
-
active: true,
|
|
113
|
-
last_used: now
|
|
114
|
-
})
|
|
115
|
-
.onConflict('fcm_token')
|
|
116
|
-
.merge({
|
|
117
|
-
identity_key: identityKey, // Update identity key in case token was reassigned
|
|
118
|
-
device_id: deviceId?.trim() ?? null,
|
|
119
|
-
platform: platform ?? null,
|
|
120
|
-
updated_at: now,
|
|
121
|
-
active: true,
|
|
122
|
-
last_used: now
|
|
123
|
-
});
|
|
124
|
-
Logger.log(`[DEBUG] Device registered successfully: ${identityKey} with token ending in ...${fcmToken.slice(-10)}`);
|
|
125
|
-
return res.status(200).json({
|
|
126
|
-
status: 'success',
|
|
127
|
-
message: 'Device registered successfully for push notifications',
|
|
128
|
-
deviceId: deviceRegistrationId
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
catch (dbError) {
|
|
132
|
-
Logger.error('[ERROR] Database error during device registration:', dbError);
|
|
133
|
-
return res.status(500).json({
|
|
134
|
-
status: 'error',
|
|
135
|
-
code: 'ERR_DATABASE_ERROR',
|
|
136
|
-
description: 'Failed to register device.'
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
Logger.error('[ERROR] Internal Server Error in registerDevice:', error);
|
|
142
|
-
return res.status(500).json({
|
|
143
|
-
status: 'error',
|
|
144
|
-
code: 'ERR_INTERNAL',
|
|
145
|
-
description: 'An internal error has occurred.'
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
//# sourceMappingURL=registerDevice.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registerDevice.js","sourceRoot":"","sources":["../../../src/routes/registerDevice.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file sendMessage.ts
|
|
3
|
-
* @description
|
|
4
|
-
* Route handler to send a message to another identity's messageBox.
|
|
5
|
-
* This route is used for P2P communication in the MessageBox system.
|
|
6
|
-
*
|
|
7
|
-
* It handles:
|
|
8
|
-
* - Validation of message structure
|
|
9
|
-
* - Validation of the recipient public key
|
|
10
|
-
* - MessageBox creation if one doesn't exist
|
|
11
|
-
* - Insertion of the message into the database
|
|
12
|
-
* - Deduplication based on messageId
|
|
13
|
-
*
|
|
14
|
-
*/
|
|
15
|
-
import knexConfig from '../../knexfile.js';
|
|
16
|
-
import * as knexLib from 'knex';
|
|
17
|
-
import { PublicKey, } from '@bsv/sdk';
|
|
18
|
-
import { Logger } from '../utils/logger.js';
|
|
19
|
-
import { sendFCMNotification } from '../utils/sendFCMNotification.js';
|
|
20
|
-
import { getRecipientFee, getServerDeliveryFee, shouldUseFCMDelivery } from '../utils/messagePermissions.js';
|
|
21
|
-
// Determine the environment (default to development)
|
|
22
|
-
const { NODE_ENV = 'development', SERVER_PRIVATE_KEY } = process.env;
|
|
23
|
-
/**
|
|
24
|
-
* Knex instance connected based on environment (development, production, or staging).
|
|
25
|
-
*/
|
|
26
|
-
const knex = knexLib.default?.(NODE_ENV === 'production' || NODE_ENV === 'staging'
|
|
27
|
-
? knexConfig.production
|
|
28
|
-
: knexConfig.development) ??
|
|
29
|
-
knexLib(NODE_ENV === 'production' || NODE_ENV === 'staging'
|
|
30
|
-
? knexConfig.production
|
|
31
|
-
: knexConfig.development);
|
|
32
|
-
// Validate critical server-side secret
|
|
33
|
-
if (SERVER_PRIVATE_KEY == null || SERVER_PRIVATE_KEY.trim() === '') {
|
|
34
|
-
throw new Error('SERVER_PRIVATE_KEY is not defined in the environment variables.');
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* @function calculateMessagePrice
|
|
38
|
-
* @description Determines the price (in satoshis) to send a message, optionally with priority.
|
|
39
|
-
*/
|
|
40
|
-
export function calculateMessagePrice(message, priority = false) {
|
|
41
|
-
const basePrice = 2; // Base fee in satoshis
|
|
42
|
-
const sizeFactor = Math.ceil(Buffer.byteLength(message, 'utf8') / 1024) * 3; // Satoshis per KB
|
|
43
|
-
return basePrice + sizeFactor;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* @openapi
|
|
47
|
-
* /sendMessage:
|
|
48
|
-
* post:
|
|
49
|
-
* summary: Send a message to a recipient’s message box
|
|
50
|
-
* description: |
|
|
51
|
-
* Inserts a message into the target recipient’s message box on the server.
|
|
52
|
-
* The recipient, message box name, and message ID must be provided.
|
|
53
|
-
* tags:
|
|
54
|
-
* - Message
|
|
55
|
-
* requestBody:
|
|
56
|
-
* required: true
|
|
57
|
-
* content:
|
|
58
|
-
* application/json:
|
|
59
|
-
* schema:
|
|
60
|
-
* type: object
|
|
61
|
-
* properties:
|
|
62
|
-
* message:
|
|
63
|
-
* type: object
|
|
64
|
-
* required:
|
|
65
|
-
* - recipient
|
|
66
|
-
* - messageBox
|
|
67
|
-
* - messageId
|
|
68
|
-
* - body
|
|
69
|
-
* properties:
|
|
70
|
-
* recipient:
|
|
71
|
-
* type: string
|
|
72
|
-
* description: Identity key of the recipient
|
|
73
|
-
* messageBox:
|
|
74
|
-
* type: string
|
|
75
|
-
* description: The name of the recipient's message box
|
|
76
|
-
* messageId:
|
|
77
|
-
* type: string
|
|
78
|
-
* description: Unique identifier for the message (usually an HMAC)
|
|
79
|
-
* body:
|
|
80
|
-
* oneOf:
|
|
81
|
-
* - type: string
|
|
82
|
-
* - type: object
|
|
83
|
-
* description: The message content
|
|
84
|
-
* responses:
|
|
85
|
-
* 200:
|
|
86
|
-
* description: Message stored successfully
|
|
87
|
-
* content:
|
|
88
|
-
* application/json:
|
|
89
|
-
* schema:
|
|
90
|
-
* type: object
|
|
91
|
-
* properties:
|
|
92
|
-
* status:
|
|
93
|
-
* type: string
|
|
94
|
-
* example: success
|
|
95
|
-
* messageId:
|
|
96
|
-
* type: string
|
|
97
|
-
* message:
|
|
98
|
-
* type: string
|
|
99
|
-
* 400:
|
|
100
|
-
* description: Invalid request or duplicate message
|
|
101
|
-
* 500:
|
|
102
|
-
* description: Internal server error
|
|
103
|
-
*/
|
|
104
|
-
/**
|
|
105
|
-
* @exports
|
|
106
|
-
* Express-compatible route definition for `/sendMessage`, used to send messages to other users.
|
|
107
|
-
* Contains metadata for auto-generation of route documentation and Swagger/OpenAPI integration.
|
|
108
|
-
*/
|
|
109
|
-
export default {
|
|
110
|
-
type: 'post',
|
|
111
|
-
path: '/sendMessage',
|
|
112
|
-
knex,
|
|
113
|
-
summary: "Use this route to send a message to a recipient's message box.",
|
|
114
|
-
parameters: {
|
|
115
|
-
message: {
|
|
116
|
-
recipient: '028d37b941208cd6b8a4c28288eda5f2f16c2b3ab0fcb6d13c18b47fe37b971fc1',
|
|
117
|
-
messageBox: 'payment_inbox',
|
|
118
|
-
messageId: 'xyz123',
|
|
119
|
-
body: '{}'
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
exampleResponse: { status: 'success' },
|
|
123
|
-
func: async (req, res) => {
|
|
124
|
-
Logger.log('[DEBUG] Processing /sendMessage request...');
|
|
125
|
-
Logger.log('[DEBUG] Request Headers:', JSON.stringify(req.headers, null, 2));
|
|
126
|
-
const senderKey = req.auth?.identityKey;
|
|
127
|
-
if (senderKey == null) {
|
|
128
|
-
return res.status(401).json({
|
|
129
|
-
status: 'error',
|
|
130
|
-
code: 'ERR_AUTH_REQUIRED',
|
|
131
|
-
description: 'Authentication required'
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
try {
|
|
135
|
-
const { message, payment } = req.body;
|
|
136
|
-
console.log('Received message send request from:', message, payment);
|
|
137
|
-
if (message == null) {
|
|
138
|
-
Logger.error('[ERROR] No message provided in request body!');
|
|
139
|
-
return res.status(400).json({
|
|
140
|
-
status: 'error',
|
|
141
|
-
code: 'ERR_MESSAGE_REQUIRED',
|
|
142
|
-
description: 'Please provide a valid message to send!'
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
if (typeof message.messageBox !== 'string' || message.messageBox.trim() === '') {
|
|
146
|
-
return res.status(400).json({ status: 'error', code: 'ERR_INVALID_MESSAGEBOX', description: 'Invalid message box.' });
|
|
147
|
-
}
|
|
148
|
-
if ((typeof message.body !== 'string' && (typeof message.body !== 'object' || message.body === null)) ||
|
|
149
|
-
(typeof message.body === 'string' && message.body.trim() === '')) {
|
|
150
|
-
return res.status(400).json({ status: 'error', code: 'ERR_INVALID_MESSAGE_BODY', description: 'Invalid message body.' });
|
|
151
|
-
}
|
|
152
|
-
// ---------- Back-compat normalization ----------
|
|
153
|
-
// Accept message.recipients (array) or message.recipient (string|array)
|
|
154
|
-
const recipientsRaw = message.recipients ?? message.recipient;
|
|
155
|
-
if (recipientsRaw == null) {
|
|
156
|
-
return res.status(400).json({
|
|
157
|
-
status: 'error',
|
|
158
|
-
code: 'ERR_RECIPIENT_REQUIRED',
|
|
159
|
-
description: 'Missing recipient(s). Provide "recipient" or "recipients".'
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
const recipients = Array.isArray(recipientsRaw)
|
|
163
|
-
? recipientsRaw
|
|
164
|
-
: [recipientsRaw];
|
|
165
|
-
const messageIdRaw = message.messageId;
|
|
166
|
-
if (messageIdRaw == null) {
|
|
167
|
-
return res.status(400).json({
|
|
168
|
-
status: 'error',
|
|
169
|
-
code: 'ERR_MESSAGEID_REQUIRED',
|
|
170
|
-
description: 'Missing messageId.'
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
const messageIds = Array.isArray(messageIdRaw)
|
|
174
|
-
? messageIdRaw
|
|
175
|
-
: [messageIdRaw];
|
|
176
|
-
// If multiple recipients but only one messageId provided, fail clearly (avoid accidental reuse)
|
|
177
|
-
if (recipients.length > 1 && messageIds.length === 1) {
|
|
178
|
-
return res.status(400).json({
|
|
179
|
-
status: 'error',
|
|
180
|
-
code: 'ERR_MESSAGEID_COUNT_MISMATCH',
|
|
181
|
-
description: `Provided 1 messageId for ${recipients.length} recipients. Provide one messageId per recipient (same order).`
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
if (messageIds.length !== recipients.length) {
|
|
185
|
-
return res.status(400).json({
|
|
186
|
-
status: 'error',
|
|
187
|
-
code: 'ERR_MESSAGEID_COUNT_MISMATCH',
|
|
188
|
-
description: `Recipients (${recipients.length}) and messageId count (${messageIds.length}) must match.`
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
// Validate each messageId
|
|
192
|
-
for (const id of messageIds) {
|
|
193
|
-
if (typeof id !== 'string' || id.trim() === '') {
|
|
194
|
-
return res.status(400).json({ status: 'error', code: 'ERR_INVALID_MESSAGEID', description: 'Each messageId must be a non-empty string.' });
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
// Validate recipient keys & build map(recipient -> messageId)
|
|
198
|
-
const recipientsTrimmed = recipients.map(r => String(r).trim());
|
|
199
|
-
const msgIdByRecipient = new Map();
|
|
200
|
-
for (let i = 0; i < recipientsTrimmed.length; i++) {
|
|
201
|
-
const r = recipientsTrimmed[i];
|
|
202
|
-
try {
|
|
203
|
-
PublicKey.fromString(r);
|
|
204
|
-
}
|
|
205
|
-
catch {
|
|
206
|
-
return res.status(400).json({
|
|
207
|
-
status: 'error',
|
|
208
|
-
code: 'ERR_INVALID_RECIPIENT_KEY',
|
|
209
|
-
description: `Invalid recipient key: ${r}`
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
msgIdByRecipient.set(r, messageIds[i]);
|
|
213
|
-
}
|
|
214
|
-
// Ensure messageBox exists for each recipient
|
|
215
|
-
const boxType = message.messageBox.trim();
|
|
216
|
-
for (const r of recipientsTrimmed) {
|
|
217
|
-
const existing = await knex('messageBox').where({ identityKey: r, type: boxType }).first();
|
|
218
|
-
if (!existing) {
|
|
219
|
-
await knex('messageBox').insert({
|
|
220
|
-
identityKey: r, type: boxType, created_at: new Date(), updated_at: new Date()
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
// ---------- Fee evaluation ----------
|
|
225
|
-
const deliveryFeeOnce = await getServerDeliveryFee(boxType);
|
|
226
|
-
const feeRows = [];
|
|
227
|
-
for (const r of recipientsTrimmed) {
|
|
228
|
-
const rf = await getRecipientFee(r, senderKey, boxType); // -1 = blocked; 0 = allow; >0 = sats required
|
|
229
|
-
if (rf === -1)
|
|
230
|
-
feeRows.push({ recipient: r, recipientFee: rf, allowed: false, blockedReason: `Messages to ${r} are blocked` });
|
|
231
|
-
else
|
|
232
|
-
feeRows.push({ recipient: r, recipientFee: rf, allowed: true });
|
|
233
|
-
}
|
|
234
|
-
// Blocked recipients short-circuit
|
|
235
|
-
const blocked = feeRows.filter(f => !f.allowed).map(f => f.recipient);
|
|
236
|
-
if (blocked.length) {
|
|
237
|
-
return res.status(403).json({
|
|
238
|
-
status: 'error',
|
|
239
|
-
code: 'ERR_DELIVERY_BLOCKED',
|
|
240
|
-
description: `Blocked recipients: ${blocked.join(', ')}`,
|
|
241
|
-
blockedRecipients: blocked
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
const anyRecipientFee = feeRows.some(f => f.recipientFee > 0);
|
|
245
|
-
const requiresPayment = (deliveryFeeOnce > 0) || anyRecipientFee;
|
|
246
|
-
// ---------- Payment internalization (batch) ----------
|
|
247
|
-
const perRecipientOutputs = new Map();
|
|
248
|
-
if (requiresPayment) {
|
|
249
|
-
if (!payment?.tx || !Array.isArray(payment.outputs)) {
|
|
250
|
-
return res.status(400).json({
|
|
251
|
-
status: 'error',
|
|
252
|
-
code: 'ERR_MISSING_PAYMENT_TX',
|
|
253
|
-
description: 'Payment transaction data is required for payable delivery.'
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
// Enforce: index 0 is server delivery output (when needed)
|
|
257
|
-
if (deliveryFeeOnce > 0) {
|
|
258
|
-
if (payment.outputs.length === 0) {
|
|
259
|
-
return res.status(400).json({
|
|
260
|
-
status: 'error',
|
|
261
|
-
code: 'ERR_MISSING_DELIVERY_OUTPUT',
|
|
262
|
-
description: 'Delivery fee required but no outputs were provided.'
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
const serverDeliveryOutput = payment.outputs[0];
|
|
266
|
-
try {
|
|
267
|
-
const { getWallet } = await import('../app.js');
|
|
268
|
-
const wallet = await getWallet();
|
|
269
|
-
const internalizeResult = await wallet.internalizeAction({
|
|
270
|
-
tx: payment.tx,
|
|
271
|
-
outputs: [serverDeliveryOutput],
|
|
272
|
-
description: payment.description ?? 'MessageBox delivery payment (batch)'
|
|
273
|
-
});
|
|
274
|
-
if (!internalizeResult.accepted) {
|
|
275
|
-
return res.status(400).json({
|
|
276
|
-
status: 'error',
|
|
277
|
-
code: 'ERR_INSUFFICIENT_PAYMENT',
|
|
278
|
-
description: 'Payment was not accepted by the server.'
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
Logger.log('[DEBUG] Internalized server delivery output at index 0');
|
|
282
|
-
}
|
|
283
|
-
catch (error) {
|
|
284
|
-
Logger.error('[ERROR] Failed to internalize delivery fee payment:', error);
|
|
285
|
-
return res.status(500).json({
|
|
286
|
-
status: 'error',
|
|
287
|
-
code: 'ERR_INTERNALIZE_FAILED',
|
|
288
|
-
description: `Failed to internalize payment: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
// ---------- Build per-recipient outputs ----------
|
|
293
|
-
const recipientSideOutputs = payment.outputs.slice(deliveryFeeOnce > 0 ? 1 : 0);
|
|
294
|
-
console.log('Recipient side outputs:', recipientSideOutputs);
|
|
295
|
-
console.log('All outputs: ', payment.outputs);
|
|
296
|
-
const feeRecipients = feeRows.filter(f => f.recipientFee > 0).map(f => f.recipient);
|
|
297
|
-
// Try explicit mapping via customInstructions (in insertionRemittance OR paymentRemittance)
|
|
298
|
-
const outputsByRecipientKey = new Map();
|
|
299
|
-
const usedIndexes = new Set();
|
|
300
|
-
for (const out of recipientSideOutputs) {
|
|
301
|
-
const raw = out?.insertionRemittance?.customInstructions ??
|
|
302
|
-
out?.paymentRemittance?.customInstructions ??
|
|
303
|
-
out?.customInstructions;
|
|
304
|
-
if (!raw)
|
|
305
|
-
continue;
|
|
306
|
-
try {
|
|
307
|
-
const instr = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
308
|
-
const key = instr?.recipientIdentityKey;
|
|
309
|
-
if (typeof key === 'string' && key.trim() !== '') {
|
|
310
|
-
if (!outputsByRecipientKey.has(key))
|
|
311
|
-
outputsByRecipientKey.set(key, []);
|
|
312
|
-
outputsByRecipientKey.get(key).push(out);
|
|
313
|
-
if (typeof out?.outputIndex === 'number') {
|
|
314
|
-
usedIndexes.add(out.outputIndex);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
catch {
|
|
319
|
-
// ignore unparsable instructions
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
if (outputsByRecipientKey.size === 0) {
|
|
323
|
-
// No explicit tags: fallback to positional mapping for recipients that require a fee
|
|
324
|
-
if (recipientSideOutputs.length < feeRecipients.length) {
|
|
325
|
-
return res.status(400).json({
|
|
326
|
-
status: 'error',
|
|
327
|
-
code: 'ERR_INSUFFICIENT_OUTPUTS',
|
|
328
|
-
description: `Expected at least ${feeRecipients.length} recipient output(s) but received ${recipientSideOutputs.length}`
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
feeRecipients.forEach((r, idx) => {
|
|
332
|
-
const out = recipientSideOutputs[idx];
|
|
333
|
-
if (!perRecipientOutputs.has(r))
|
|
334
|
-
perRecipientOutputs.set(r, []);
|
|
335
|
-
perRecipientOutputs.get(r).push(out);
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
// Use tagged outputs where present
|
|
340
|
-
for (const r of feeRecipients) {
|
|
341
|
-
const tagged = outputsByRecipientKey.get(r) ?? [];
|
|
342
|
-
if (tagged.length > 0) {
|
|
343
|
-
perRecipientOutputs.set(r, tagged);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
// For any remaining fee recipients without tags, allocate unused outputs (positional)
|
|
347
|
-
const unmapped = feeRecipients.filter(r => !perRecipientOutputs.has(r));
|
|
348
|
-
if (unmapped.length > 0) {
|
|
349
|
-
const remaining = recipientSideOutputs.filter(o => {
|
|
350
|
-
const idx = o?.outputIndex;
|
|
351
|
-
return typeof idx === 'number' ? !usedIndexes.has(idx) : true;
|
|
352
|
-
});
|
|
353
|
-
if (remaining.length < unmapped.length) {
|
|
354
|
-
return res.status(400).json({
|
|
355
|
-
status: 'error',
|
|
356
|
-
code: 'ERR_INSUFFICIENT_OUTPUTS',
|
|
357
|
-
description: `Expected at least ${unmapped.length} additional recipient output(s) but only ${remaining.length} remain`
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
unmapped.forEach((r, i) => {
|
|
361
|
-
const out = remaining[i];
|
|
362
|
-
if (!perRecipientOutputs.has(r))
|
|
363
|
-
perRecipientOutputs.set(r, []);
|
|
364
|
-
perRecipientOutputs.get(r).push(out);
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
// Final safety check
|
|
368
|
-
for (const r of feeRecipients) {
|
|
369
|
-
if (!perRecipientOutputs.has(r) || perRecipientOutputs.get(r).length === 0) {
|
|
370
|
-
return res.status(400).json({
|
|
371
|
-
status: 'error',
|
|
372
|
-
code: 'ERR_MISSING_RECIPIENT_OUTPUTS',
|
|
373
|
-
description: `Recipient fee required but no outputs were provided for ${r}`
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
// ---------- Store messages (one per recipient) ----------
|
|
380
|
-
const results = [];
|
|
381
|
-
for (const { recipient: r } of feeRows) {
|
|
382
|
-
const mb = await knex('messageBox')
|
|
383
|
-
.where({ identityKey: r, type: boxType })
|
|
384
|
-
.select('messageBoxId')
|
|
385
|
-
.first();
|
|
386
|
-
const perRecipientMessageId = msgIdByRecipient.get(r);
|
|
387
|
-
if (!perRecipientMessageId) {
|
|
388
|
-
return res.status(400).json({
|
|
389
|
-
status: 'error',
|
|
390
|
-
code: 'ERR_INVALID_MESSAGEID',
|
|
391
|
-
description: `Missing messageId for recipient ${r}`
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
const perRecipientPayment = perRecipientOutputs.has(r) && req.body.payment
|
|
395
|
-
? { ...req.body.payment, outputs: perRecipientOutputs.get(r) }
|
|
396
|
-
: undefined;
|
|
397
|
-
const storedBody = {
|
|
398
|
-
message: message.body,
|
|
399
|
-
...(perRecipientPayment && { payment: perRecipientPayment })
|
|
400
|
-
};
|
|
401
|
-
try {
|
|
402
|
-
await knex('messages')
|
|
403
|
-
.insert({
|
|
404
|
-
messageId: perRecipientMessageId,
|
|
405
|
-
messageBoxId: mb?.messageBoxId ?? null,
|
|
406
|
-
sender: senderKey,
|
|
407
|
-
recipient: r,
|
|
408
|
-
body: JSON.stringify(storedBody),
|
|
409
|
-
created_at: new Date(),
|
|
410
|
-
updated_at: new Date()
|
|
411
|
-
})
|
|
412
|
-
.onConflict('messageId')
|
|
413
|
-
.ignore();
|
|
414
|
-
results.push({ recipient: r, messageId: perRecipientMessageId });
|
|
415
|
-
}
|
|
416
|
-
catch (error) {
|
|
417
|
-
if (error?.code === 'ER_DUP_ENTRY') {
|
|
418
|
-
return res.status(400).json({
|
|
419
|
-
status: 'error',
|
|
420
|
-
code: 'ERR_DUPLICATE_MESSAGE',
|
|
421
|
-
description: 'Duplicate message.'
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
throw error;
|
|
425
|
-
}
|
|
426
|
-
try {
|
|
427
|
-
if (shouldUseFCMDelivery(boxType)) {
|
|
428
|
-
await sendFCMNotification(r, { title: 'New Message', messageId: perRecipientMessageId });
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
catch (deliveryError) {
|
|
432
|
-
Logger.error('[ERROR] Error processing FCM delivery:', deliveryError);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
return res.status(200).json({
|
|
436
|
-
status: 'success',
|
|
437
|
-
message: `Your message has been sent to ${results.length} recipient(s).`,
|
|
438
|
-
results
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
catch (error) {
|
|
442
|
-
Logger.error('[ERROR] Internal Server Error:', error);
|
|
443
|
-
return res.status(500).json({
|
|
444
|
-
status: 'error',
|
|
445
|
-
code: 'ERR_INTERNAL',
|
|
446
|
-
description: 'An internal error has occurred.'
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
//# sourceMappingURL=sendMessage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sendMessage.js","sourceRoot":"","sources":["../../../src/routes/sendMessage.ts"],"names":[],"mappings":"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"}
|