@bopen-io/messagebox-server 1.2.2 → 1.2.4

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 (143) hide show
  1. package/out/knexfile.js +25 -0
  2. package/out/knexfile.js.map +1 -0
  3. package/out/src/__tests/compose.test.js +25 -0
  4. package/out/src/__tests/compose.test.js.map +1 -0
  5. package/out/src/app.js +162 -0
  6. package/out/src/app.js.map +1 -0
  7. package/out/src/compose.js +239 -0
  8. package/out/src/compose.js.map +1 -0
  9. package/out/src/config/firebase.js +150 -0
  10. package/out/src/config/firebase.js.map +1 -0
  11. package/out/src/context.js +23 -0
  12. package/out/src/context.js.map +1 -0
  13. package/out/src/index.js +311 -0
  14. package/out/src/index.js.map +1 -0
  15. package/out/src/migrations/2022-12-28-001-initial-migration.js +28 -0
  16. package/out/src/migrations/2022-12-28-001-initial-migration.js.map +1 -0
  17. package/out/src/migrations/2023-01-17-messages-update.js +11 -0
  18. package/out/src/migrations/2023-01-17-messages-update.js.map +1 -0
  19. package/out/src/migrations/2024-03-05-001-messageID-upgrade.js +21 -0
  20. package/out/src/migrations/2024-03-05-001-messageID-upgrade.js.map +1 -0
  21. package/out/src/migrations/2025-01-31-001-notification-permissions.js +59 -0
  22. package/out/src/migrations/2025-01-31-001-notification-permissions.js.map +1 -0
  23. package/out/src/migrations/2025-01-31-002-device-registrations.js +24 -0
  24. package/out/src/migrations/2025-01-31-002-device-registrations.js.map +1 -0
  25. package/out/src/routes/__tests/acknowledgeMessage.test.js +135 -0
  26. package/out/src/routes/__tests/acknowledgeMessage.test.js.map +1 -0
  27. package/out/src/routes/__tests/listMessages.test.js +217 -0
  28. package/out/src/routes/__tests/listMessages.test.js.map +1 -0
  29. package/out/src/routes/__tests/sendMessage.test.js +313 -0
  30. package/out/src/routes/__tests/sendMessage.test.js.map +1 -0
  31. package/out/src/routes/acknowledgeMessage.js +133 -0
  32. package/out/src/routes/acknowledgeMessage.js.map +1 -0
  33. package/out/src/routes/index.js +17 -0
  34. package/out/src/routes/index.js.map +1 -0
  35. package/out/src/routes/listDevices.js +63 -0
  36. package/out/src/routes/listDevices.js.map +1 -0
  37. package/out/src/routes/listMessages.js +176 -0
  38. package/out/src/routes/listMessages.js.map +1 -0
  39. package/out/src/routes/permissions/getPermission.js +138 -0
  40. package/out/src/routes/permissions/getPermission.js.map +1 -0
  41. package/out/src/routes/permissions/getQuote.js +165 -0
  42. package/out/src/routes/permissions/getQuote.js.map +1 -0
  43. package/out/src/routes/permissions/index.js +12 -0
  44. package/out/src/routes/permissions/index.js.map +1 -0
  45. package/out/src/routes/permissions/listPermissions.js +179 -0
  46. package/out/src/routes/permissions/listPermissions.js.map +1 -0
  47. package/out/src/routes/permissions/setPermission.js +137 -0
  48. package/out/src/routes/permissions/setPermission.js.map +1 -0
  49. package/out/src/routes/registerDevice.js +139 -0
  50. package/out/src/routes/registerDevice.js.map +1 -0
  51. package/out/src/routes/sendMessage.js +438 -0
  52. package/out/src/routes/sendMessage.js.map +1 -0
  53. package/out/src/runtimeDeps.js +15 -0
  54. package/out/src/runtimeDeps.js.map +1 -0
  55. package/out/src/swagger.js +48 -0
  56. package/out/src/swagger.js.map +1 -0
  57. package/out/src/telemetry.js +134 -0
  58. package/out/src/telemetry.js.map +1 -0
  59. package/out/src/types/messagePermissions.js +2 -0
  60. package/out/src/types/messagePermissions.js.map +1 -0
  61. package/out/src/types/notifications.js +2 -0
  62. package/out/src/types/notifications.js.map +1 -0
  63. package/out/src/utils/logger.js +90 -0
  64. package/out/src/utils/logger.js.map +1 -0
  65. package/out/src/utils/messagePermissions.js +115 -0
  66. package/out/src/utils/messagePermissions.js.map +1 -0
  67. package/out/src/utils/sendFCMNotification.js +110 -0
  68. package/out/src/utils/sendFCMNotification.js.map +1 -0
  69. package/out/tsconfig.tsbuildinfo +1 -0
  70. package/out/types/jest.config.d.ts +4 -0
  71. package/out/types/jest.config.d.ts.map +1 -0
  72. package/out/types/jest.config.integration.d.ts +5 -0
  73. package/out/types/jest.config.integration.d.ts.map +1 -0
  74. package/out/types/knexfile.d.ts +6 -0
  75. package/out/types/knexfile.d.ts.map +1 -0
  76. package/out/types/src/__tests/compose.test.d.ts +2 -0
  77. package/out/types/src/__tests/compose.test.d.ts.map +1 -0
  78. package/out/types/src/app.d.ts +63 -0
  79. package/out/types/src/app.d.ts.map +1 -0
  80. package/out/types/src/compose.d.ts +22 -0
  81. package/out/types/src/compose.d.ts.map +1 -0
  82. package/out/types/src/config/firebase.d.ts +34 -0
  83. package/out/types/src/config/firebase.d.ts.map +1 -0
  84. package/out/types/src/context.d.ts +23 -0
  85. package/out/types/src/context.d.ts.map +1 -0
  86. package/out/types/src/index.d.ts +43 -0
  87. package/out/types/src/index.d.ts.map +1 -0
  88. package/out/types/src/migrations/2022-12-28-001-initial-migration.d.ts +4 -0
  89. package/out/types/src/migrations/2022-12-28-001-initial-migration.d.ts.map +1 -0
  90. package/out/types/src/migrations/2023-01-17-messages-update.d.ts +4 -0
  91. package/out/types/src/migrations/2023-01-17-messages-update.d.ts.map +1 -0
  92. package/out/types/src/migrations/2024-03-05-001-messageID-upgrade.d.ts +4 -0
  93. package/out/types/src/migrations/2024-03-05-001-messageID-upgrade.d.ts.map +1 -0
  94. package/out/types/src/migrations/2025-01-31-001-notification-permissions.d.ts +4 -0
  95. package/out/types/src/migrations/2025-01-31-001-notification-permissions.d.ts.map +1 -0
  96. package/out/types/src/migrations/2025-01-31-002-device-registrations.d.ts +4 -0
  97. package/out/types/src/migrations/2025-01-31-002-device-registrations.d.ts.map +1 -0
  98. package/out/types/src/routes/__tests/acknowledgeMessage.test.d.ts +2 -0
  99. package/out/types/src/routes/__tests/acknowledgeMessage.test.d.ts.map +1 -0
  100. package/out/types/src/routes/__tests/listMessages.test.d.ts +2 -0
  101. package/out/types/src/routes/__tests/listMessages.test.d.ts.map +1 -0
  102. package/out/types/src/routes/__tests/sendMessage.test.d.ts +2 -0
  103. package/out/types/src/routes/__tests/sendMessage.test.d.ts.map +1 -0
  104. package/out/types/src/routes/acknowledgeMessage.d.ts +100 -0
  105. package/out/types/src/routes/acknowledgeMessage.d.ts.map +1 -0
  106. package/out/types/src/routes/index.d.ts +11 -0
  107. package/out/types/src/routes/index.d.ts.map +1 -0
  108. package/out/types/src/routes/listDevices.d.ts +19 -0
  109. package/out/types/src/routes/listDevices.d.ts.map +1 -0
  110. package/out/types/src/routes/listMessages.d.ts +124 -0
  111. package/out/types/src/routes/listMessages.d.ts.map +1 -0
  112. package/out/types/src/routes/permissions/getPermission.d.ts +46 -0
  113. package/out/types/src/routes/permissions/getPermission.d.ts.map +1 -0
  114. package/out/types/src/routes/permissions/getQuote.d.ts +50 -0
  115. package/out/types/src/routes/permissions/getQuote.d.ts.map +1 -0
  116. package/out/types/src/routes/permissions/index.d.ts +18 -0
  117. package/out/types/src/routes/permissions/index.d.ts.map +1 -0
  118. package/out/types/src/routes/permissions/listPermissions.d.ts +106 -0
  119. package/out/types/src/routes/permissions/listPermissions.d.ts.map +1 -0
  120. package/out/types/src/routes/permissions/setPermission.d.ts +53 -0
  121. package/out/types/src/routes/permissions/setPermission.d.ts.map +1 -0
  122. package/out/types/src/routes/registerDevice.d.ts +67 -0
  123. package/out/types/src/routes/registerDevice.d.ts.map +1 -0
  124. package/out/types/src/routes/sendMessage.d.ts +140 -0
  125. package/out/types/src/routes/sendMessage.d.ts.map +1 -0
  126. package/out/types/src/runtimeDeps.d.ts +17 -0
  127. package/out/types/src/runtimeDeps.d.ts.map +1 -0
  128. package/out/types/src/swagger.d.ts +3 -0
  129. package/out/types/src/swagger.d.ts.map +1 -0
  130. package/out/types/src/telemetry.d.ts +2 -0
  131. package/out/types/src/telemetry.d.ts.map +1 -0
  132. package/out/types/src/types/messagePermissions.d.ts +15 -0
  133. package/out/types/src/types/messagePermissions.d.ts.map +1 -0
  134. package/out/types/src/types/notifications.d.ts +20 -0
  135. package/out/types/src/types/notifications.d.ts.map +1 -0
  136. package/out/types/src/utils/logger.d.ts +17 -0
  137. package/out/types/src/utils/logger.d.ts.map +1 -0
  138. package/out/types/src/utils/messagePermissions.d.ts +29 -0
  139. package/out/types/src/utils/messagePermissions.d.ts.map +1 -0
  140. package/out/types/src/utils/sendFCMNotification.d.ts +22 -0
  141. package/out/types/src/utils/sendFCMNotification.d.ts.map +1 -0
  142. package/package.json +1 -1
  143. package/src/utils/logger.ts +6 -2
@@ -0,0 +1,179 @@
1
+ import { Logger } from '../../utils/logger.js';
2
+ import { runtimeDeps } from '../../runtimeDeps.js';
3
+ /**
4
+ * @swagger
5
+ * /permissions/list:
6
+ * get:
7
+ * summary: List message permissions for the authenticated user
8
+ * description: Retrieve all permissions set by the authenticated user with optional filtering and pagination
9
+ * tags:
10
+ * - Permissions
11
+ * parameters:
12
+ * - in: query
13
+ * name: messageBox
14
+ * required: false
15
+ * schema:
16
+ * type: string
17
+ * description: Optional messageBox type filter (e.g., 'notifications', 'inbox')
18
+ * - in: query
19
+ * name: limit
20
+ * required: false
21
+ * schema:
22
+ * type: integer
23
+ * minimum: 1
24
+ * maximum: 1000
25
+ * default: 100
26
+ * description: Maximum number of permissions to return
27
+ * - in: query
28
+ * name: offset
29
+ * required: false
30
+ * schema:
31
+ * type: integer
32
+ * minimum: 0
33
+ * default: 0
34
+ * description: Number of permissions to skip for pagination
35
+ * - in: query
36
+ * name: createdAtOrder
37
+ * required: false
38
+ * schema:
39
+ * type: string
40
+ * enum: ['asc', 'desc']
41
+ * default: 'desc'
42
+ * description: Sort order for created_at date (asc=oldest first, desc=newest first)
43
+ * responses:
44
+ * 200:
45
+ * description: Permissions retrieved successfully
46
+ * content:
47
+ * application/json:
48
+ * schema:
49
+ * type: object
50
+ * properties:
51
+ * status:
52
+ * type: string
53
+ * example: 'success'
54
+ * permissions:
55
+ * type: array
56
+ * items:
57
+ * type: object
58
+ * properties:
59
+ * sender:
60
+ * type: string
61
+ * nullable: true
62
+ * description: Sender identity key (null for box-wide defaults)
63
+ * messageBox:
64
+ * type: string
65
+ * description: MessageBox type
66
+ * recipientFee:
67
+ * type: integer
68
+ * description: Fee setting (-1=block all, 0=always allow, >0=satoshi amount)
69
+ * created_at:
70
+ * type: string
71
+ * format: date-time
72
+ * updated_at:
73
+ * type: string
74
+ * format: date-time
75
+ * total_count:
76
+ * type: integer
77
+ * description: Total number of permissions (useful for pagination)
78
+ * 400:
79
+ * description: Invalid query parameters
80
+ * 401:
81
+ * description: Unauthorized - authentication required
82
+ * 500:
83
+ * description: Internal server error
84
+ */
85
+ export default {
86
+ type: 'get',
87
+ path: '/permissions/list',
88
+ /**
89
+ * List message permissions for the authenticated user
90
+ *
91
+ * @param {ListPermissionsRequest} req - Authenticated request with query parameters
92
+ * @param {Response} res - Express response object
93
+ * @returns {Promise<Response>} JSON response with permissions list
94
+ */
95
+ func: async (req, res) => {
96
+ Logger.log('[DEBUG] Processing /permissions/list request...');
97
+ try {
98
+ // Validate authentication
99
+ if (req.auth?.identityKey == null) {
100
+ return res.status(401).json({
101
+ status: 'error',
102
+ code: 'ERR_UNAUTHORIZED',
103
+ description: 'Authentication required'
104
+ });
105
+ }
106
+ // Parse and validate query parameters
107
+ const { messageBox, limit: limitStr, offset: offsetStr, createdAtOrder } = req.query;
108
+ const limit = limitStr != null ? Number.parseInt(limitStr, 10) : 100;
109
+ const offset = offsetStr != null ? Number.parseInt(offsetStr, 10) : 0;
110
+ const sortOrder = createdAtOrder === 'asc' ? 'asc' : 'desc'; // Default to 'desc'
111
+ // Validate pagination parameters
112
+ if (Number.isNaN(limit) || limit < 1 || limit > 1000) {
113
+ return res.status(400).json({
114
+ status: 'error',
115
+ code: 'ERR_INVALID_LIMIT',
116
+ description: 'Limit must be a number between 1 and 1000'
117
+ });
118
+ }
119
+ if (Number.isNaN(offset) || offset < 0) {
120
+ return res.status(400).json({
121
+ status: 'error',
122
+ code: 'ERR_INVALID_OFFSET',
123
+ description: 'Offset must be a non-negative number'
124
+ });
125
+ }
126
+ // Validate identity key format
127
+ const recipientKey = req.auth.identityKey;
128
+ Logger.log(`[DEBUG] Listing permissions for recipient: ${recipientKey}, messageBox: ${messageBox ?? 'all'}, limit: ${limit}, offset: ${offset}, createdAtOrder: ${sortOrder}`);
129
+ // Build base query
130
+ let query = runtimeDeps.knex('message_permissions')
131
+ .select([
132
+ 'sender',
133
+ 'message_box',
134
+ 'recipient_fee',
135
+ 'created_at',
136
+ 'updated_at'
137
+ ])
138
+ .where('recipient', recipientKey)
139
+ .orderBy([
140
+ { column: 'message_box', order: 'asc' },
141
+ { column: 'sender', order: 'asc', nulls: 'first' }, // Box-wide (null) first
142
+ { column: 'created_at', order: sortOrder }
143
+ ]);
144
+ // Apply messageBox filter if provided
145
+ if (messageBox != null) {
146
+ query = query.where('message_box', messageBox);
147
+ }
148
+ // Get total count for pagination info (before applying limit/offset)
149
+ const countQuery = query.clone().clearSelect().clearOrder().count('* as count');
150
+ const [{ count: totalCount }] = await countQuery;
151
+ const total = Number.parseInt(String(totalCount), 10);
152
+ // Apply pagination
153
+ const permissions = await query
154
+ .limit(limit)
155
+ .offset(offset);
156
+ Logger.log(`[DEBUG] Found ${permissions.length} permissions (${total} total)`);
157
+ return res.status(200).json({
158
+ status: 'success',
159
+ permissions: permissions.map(p => ({
160
+ sender: p.sender, // null for box-wide defaults
161
+ messageBox: p.message_box,
162
+ recipientFee: p.recipient_fee,
163
+ createdAt: p.created_at,
164
+ updatedAt: p.updated_at
165
+ })),
166
+ totalCount: total
167
+ });
168
+ }
169
+ catch (error) {
170
+ Logger.error('[ERROR] Error listing permissions:', error);
171
+ return res.status(500).json({
172
+ status: 'error',
173
+ code: 'ERR_LIST_PERMISSIONS_FAILED',
174
+ description: 'Failed to list permissions'
175
+ });
176
+ }
177
+ }
178
+ };
179
+ //# sourceMappingURL=listPermissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listPermissions.js","sourceRoot":"","sources":["../../../../src/routes/permissions/listPermissions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ import { PublicKey } from '@bsv/sdk';
2
+ import { Logger } from '../../utils/logger.js';
3
+ import { setMessagePermission } from '../../utils/messagePermissions.js';
4
+ /**
5
+ * @swagger
6
+ * /permissions/set:
7
+ * post:
8
+ * summary: Set message permission for a sender/box combination or box-wide default
9
+ * description: Set permission level for receiving messages. If sender is provided, sets permission for that specific sender. If sender is omitted, sets box-wide default for all senders.
10
+ * tags:
11
+ * - Permissions
12
+ * requestBody:
13
+ * required: true
14
+ * content:
15
+ * application/json:
16
+ * schema:
17
+ * type: object
18
+ * required:
19
+ * - messageBox
20
+ * - recipientFee
21
+ * properties:
22
+ * sender:
23
+ * type: string
24
+ * description: identityKey of the sender (optional - if omitted, sets box-wide default for all senders)
25
+ * messageBox:
26
+ * type: string
27
+ * description: messageBox type (e.g., 'notifications', 'inbox')
28
+ * recipientFee:
29
+ * type: integer
30
+ * description: Fee level (-1=blocked, 0=always allow, >0=satoshi amount required)
31
+ * responses:
32
+ * 200:
33
+ * description: Permission successfully set/updated
34
+ * 400:
35
+ * description: Invalid request data
36
+ * 401:
37
+ * description: Authentication required
38
+ * 500:
39
+ * description: Internal server error
40
+ */
41
+ export default {
42
+ type: 'post',
43
+ path: '/permissions/set',
44
+ func: async (req, res) => {
45
+ try {
46
+ Logger.log('[DEBUG] Processing set message permission request');
47
+ // Validate authentication
48
+ const recipient = req.auth?.identityKey;
49
+ if (recipient == null) {
50
+ Logger.log('[DEBUG] Authentication required for set permission');
51
+ return res.status(401).json({
52
+ status: 'error',
53
+ code: 'ERR_AUTHENTICATION_REQUIRED',
54
+ description: 'Authentication required.'
55
+ });
56
+ }
57
+ const { sender, messageBox, recipientFee } = req.body;
58
+ // Validate request body (sender is optional)
59
+ if (messageBox == null || typeof recipientFee !== 'number') {
60
+ Logger.log('[DEBUG] Invalid request body for set permission');
61
+ return res.status(400).json({
62
+ status: 'error',
63
+ code: 'ERR_INVALID_REQUEST',
64
+ description: 'messageBox (string) and recipientFee (number) are required. sender (string) is optional for box-wide settings.'
65
+ });
66
+ }
67
+ // Validate sender public key format only if provided
68
+ if (sender != null) {
69
+ try {
70
+ PublicKey.fromString(sender);
71
+ }
72
+ catch (error) {
73
+ Logger.log('[DEBUG] Invalid sender public key format');
74
+ return res.status(400).json({
75
+ status: 'error',
76
+ code: 'ERR_INVALID_PUBLIC_KEY',
77
+ description: 'Invalid sender public key format.'
78
+ });
79
+ }
80
+ }
81
+ // Validate recipientFee value
82
+ if (!Number.isInteger(recipientFee)) {
83
+ Logger.log('[DEBUG] Invalid recipientFee value - must be integer');
84
+ return res.status(400).json({
85
+ status: 'error',
86
+ code: 'ERR_INVALID_FEE_VALUE',
87
+ description: 'recipientFee must be an integer (-1, 0, or positive number).'
88
+ });
89
+ }
90
+ // Validate messageBox value
91
+ if (typeof messageBox !== 'string' || messageBox.trim() === '') {
92
+ Logger.log('[DEBUG] Invalid messageBox value');
93
+ return res.status(400).json({
94
+ status: 'error',
95
+ code: 'ERR_INVALID_MESSAGE_BOX',
96
+ description: 'messageBox must be a non-empty string.'
97
+ });
98
+ }
99
+ // Set the message permission (convert undefined sender to null for box-wide)
100
+ const success = await setMessagePermission(recipient, sender ?? null, messageBox, recipientFee);
101
+ if (success == null) {
102
+ return res.status(500).json({
103
+ status: 'error',
104
+ code: 'ERR_DATABASE_ERROR',
105
+ description: 'Failed to update message permission.'
106
+ });
107
+ }
108
+ const isBoxWide = sender == null;
109
+ Logger.log(`[DEBUG] Successfully updated message permission: ${sender ?? 'BOX-WIDE'} -> ${recipient} (${messageBox}), fee: ${recipientFee}`);
110
+ let description;
111
+ const senderText = isBoxWide ? 'all senders' : sender;
112
+ const actionText = isBoxWide ? 'Box-wide default for' : 'Messages from';
113
+ if (recipientFee === -1) {
114
+ description = `${actionText} ${senderText} to ${messageBox} ${isBoxWide ? 'is' : 'are'} now blocked.`;
115
+ }
116
+ else if (recipientFee === 0) {
117
+ description = `${actionText} ${senderText} to ${messageBox} ${isBoxWide ? 'is' : 'are'} now always allowed.`;
118
+ }
119
+ else {
120
+ description = `${actionText} ${senderText} to ${messageBox} now require${isBoxWide ? 's' : ''} ${recipientFee} satoshis.`;
121
+ }
122
+ return res.status(200).json({
123
+ status: 'success',
124
+ description
125
+ });
126
+ }
127
+ catch (error) {
128
+ Logger.error('[ERROR] Internal Server Error in set permission:', error);
129
+ return res.status(500).json({
130
+ status: 'error',
131
+ code: 'ERR_INTERNAL',
132
+ description: 'An internal error has occurred.'
133
+ });
134
+ }
135
+ }
136
+ };
137
+ //# sourceMappingURL=setPermission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setPermission.js","sourceRoot":"","sources":["../../../../src/routes/permissions/setPermission.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ import { Logger } from '../utils/logger.js';
2
+ import { runtimeDeps } from '../runtimeDeps.js';
3
+ /**
4
+ * @swagger
5
+ * /registerDevice:
6
+ * post:
7
+ * summary: Register device for push notifications
8
+ * description: Register a device's FCM token for receiving push notifications
9
+ * tags:
10
+ * - Device
11
+ * requestBody:
12
+ * required: true
13
+ * content:
14
+ * application/json:
15
+ * schema:
16
+ * type: object
17
+ * required:
18
+ * - fcmToken
19
+ * properties:
20
+ * fcmToken:
21
+ * type: string
22
+ * description: Firebase Cloud Messaging token
23
+ * deviceId:
24
+ * type: string
25
+ * description: Optional device identifier
26
+ * platform:
27
+ * type: string
28
+ * description: Device platform (ios, android, web)
29
+ * enum: [ios, android, web]
30
+ * responses:
31
+ * 200:
32
+ * description: Device registered successfully
33
+ * content:
34
+ * application/json:
35
+ * schema:
36
+ * type: object
37
+ * properties:
38
+ * status:
39
+ * type: string
40
+ * example: success
41
+ * message:
42
+ * type: string
43
+ * example: Device registered successfully
44
+ * deviceId:
45
+ * type: integer
46
+ * description: Database ID of the registered device
47
+ * 400:
48
+ * description: Invalid request parameters
49
+ * 401:
50
+ * description: Authentication required
51
+ * 500:
52
+ * description: Internal server error
53
+ */
54
+ export default {
55
+ type: 'post',
56
+ path: '/registerDevice',
57
+ func: async (req, res) => {
58
+ try {
59
+ Logger.log('[DEBUG] Processing device registration request');
60
+ // Validate authentication
61
+ const identityKey = req.auth?.identityKey;
62
+ if (identityKey == null) {
63
+ Logger.log('[DEBUG] Authentication required for device registration');
64
+ return res.status(401).json({
65
+ status: 'error',
66
+ code: 'ERR_AUTHENTICATION_REQUIRED',
67
+ description: 'Authentication required.'
68
+ });
69
+ }
70
+ const { fcmToken, deviceId, platform } = req.body;
71
+ // Validate required fields
72
+ if (fcmToken == null || typeof fcmToken !== 'string' || fcmToken.trim() === '') {
73
+ Logger.log('[DEBUG] Invalid FCM token provided');
74
+ return res.status(400).json({
75
+ status: 'error',
76
+ code: 'ERR_INVALID_FCM_TOKEN',
77
+ description: 'fcmToken is required and must be a non-empty string.'
78
+ });
79
+ }
80
+ // Validate platform if provided
81
+ const validPlatforms = ['ios', 'android', 'web'];
82
+ if (platform != null && !validPlatforms.includes(platform)) {
83
+ Logger.log('[DEBUG] Invalid platform provided');
84
+ return res.status(400).json({
85
+ status: 'error',
86
+ code: 'ERR_INVALID_PLATFORM',
87
+ description: 'platform must be one of: ios, android, web'
88
+ });
89
+ }
90
+ try {
91
+ // Insert or update device registration
92
+ const now = new Date();
93
+ const [deviceRegistrationId] = await runtimeDeps.knex('device_registrations')
94
+ .insert({
95
+ identity_key: identityKey,
96
+ fcm_token: fcmToken.trim(),
97
+ device_id: deviceId?.trim() ?? null,
98
+ platform: platform ?? null,
99
+ created_at: now,
100
+ updated_at: now,
101
+ active: true,
102
+ last_used: now
103
+ })
104
+ .onConflict('fcm_token')
105
+ .merge({
106
+ identity_key: identityKey, // Update identity key in case token was reassigned
107
+ device_id: deviceId?.trim() ?? null,
108
+ platform: platform ?? null,
109
+ updated_at: now,
110
+ active: true,
111
+ last_used: now
112
+ });
113
+ Logger.log(`[DEBUG] Device registered successfully: ${identityKey} with token ending in ...${fcmToken.slice(-10)}`);
114
+ return res.status(200).json({
115
+ status: 'success',
116
+ message: 'Device registered successfully for push notifications',
117
+ deviceId: deviceRegistrationId
118
+ });
119
+ }
120
+ catch (dbError) {
121
+ Logger.error('[ERROR] Database error during device registration:', dbError);
122
+ return res.status(500).json({
123
+ status: 'error',
124
+ code: 'ERR_DATABASE_ERROR',
125
+ description: 'Failed to register device.'
126
+ });
127
+ }
128
+ }
129
+ catch (error) {
130
+ Logger.error('[ERROR] Internal Server Error in registerDevice:', error);
131
+ return res.status(500).json({
132
+ status: 'error',
133
+ code: 'ERR_INTERNAL',
134
+ description: 'An internal error has occurred.'
135
+ });
136
+ }
137
+ }
138
+ };
139
+ //# sourceMappingURL=registerDevice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registerDevice.js","sourceRoot":"","sources":["../../../src/routes/registerDevice.ts"],"names":[],"mappings":"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"}