piece-signal-cli-rest-api 0.2.0 → 0.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 (179) hide show
  1. package/package.json +26 -4
  2. package/src/index.d.ts +8 -0
  3. package/src/index.js +90 -0
  4. package/src/index.js.map +1 -0
  5. package/src/lib/actions/add-admins-to-group.d.ts +12 -0
  6. package/src/lib/actions/add-admins-to-group.js +45 -0
  7. package/src/lib/actions/add-admins-to-group.js.map +1 -0
  8. package/src/lib/actions/add-device.d.ts +11 -0
  9. package/src/lib/actions/add-device.js +40 -0
  10. package/src/lib/actions/add-device.js.map +1 -0
  11. package/src/lib/actions/add-members-to-group.d.ts +12 -0
  12. package/src/lib/actions/add-members-to-group.js +45 -0
  13. package/src/lib/actions/add-members-to-group.js.map +1 -0
  14. package/src/lib/actions/block-group.d.ts +11 -0
  15. package/src/lib/actions/block-group.js +37 -0
  16. package/src/lib/actions/block-group.js.map +1 -0
  17. package/src/lib/actions/create-group.d.ts +18 -0
  18. package/src/lib/actions/create-group.js +117 -0
  19. package/src/lib/actions/create-group.js.map +1 -0
  20. package/src/lib/actions/delete-group.d.ts +11 -0
  21. package/src/lib/actions/delete-group.js +37 -0
  22. package/src/lib/actions/delete-group.js.map +1 -0
  23. package/src/lib/actions/get-contact.d.ts +11 -0
  24. package/src/lib/actions/get-contact.js +37 -0
  25. package/src/lib/actions/get-contact.js.map +1 -0
  26. package/src/lib/actions/get-group.d.ts +11 -0
  27. package/src/lib/actions/get-group.js +37 -0
  28. package/src/lib/actions/get-group.js.map +1 -0
  29. package/src/lib/actions/get-qr-code-link.d.ts +11 -0
  30. package/src/lib/actions/get-qr-code-link.js +60 -0
  31. package/src/lib/actions/get-qr-code-link.js.map +1 -0
  32. package/src/lib/actions/join-group.d.ts +11 -0
  33. package/src/lib/actions/join-group.js +37 -0
  34. package/src/lib/actions/join-group.js.map +1 -0
  35. package/src/lib/actions/list-accounts.d.ts +8 -0
  36. package/src/lib/actions/list-accounts.js +23 -0
  37. package/src/lib/actions/list-accounts.js.map +1 -0
  38. package/src/lib/actions/list-attachments.d.ts +8 -0
  39. package/src/lib/actions/list-attachments.js +23 -0
  40. package/src/lib/actions/list-attachments.js.map +1 -0
  41. package/src/lib/actions/list-contacts.d.ts +10 -0
  42. package/src/lib/actions/list-contacts.js +32 -0
  43. package/src/lib/actions/list-contacts.js.map +1 -0
  44. package/src/lib/actions/list-devices.d.ts +10 -0
  45. package/src/lib/actions/list-devices.js +32 -0
  46. package/src/lib/actions/list-devices.js.map +1 -0
  47. package/src/lib/actions/list-groups.d.ts +10 -0
  48. package/src/lib/actions/list-groups.js +32 -0
  49. package/src/lib/actions/list-groups.js.map +1 -0
  50. package/src/lib/actions/list-identities.d.ts +10 -0
  51. package/src/lib/actions/list-identities.js +32 -0
  52. package/src/lib/actions/list-identities.js.map +1 -0
  53. package/src/lib/actions/quit-group.d.ts +11 -0
  54. package/src/lib/actions/quit-group.js +37 -0
  55. package/src/lib/actions/quit-group.js.map +1 -0
  56. package/src/lib/actions/receive-messages.d.ts +15 -0
  57. package/src/lib/actions/receive-messages.js +100 -0
  58. package/src/lib/actions/receive-messages.js.map +1 -0
  59. package/src/lib/actions/remote-delete-message.d.ts +12 -0
  60. package/src/lib/actions/remote-delete-message.js +46 -0
  61. package/src/lib/actions/remote-delete-message.js.map +1 -0
  62. package/src/lib/actions/remove-admins-from-group.d.ts +12 -0
  63. package/src/lib/actions/remove-admins-from-group.js +45 -0
  64. package/src/lib/actions/remove-admins-from-group.js.map +1 -0
  65. package/src/lib/actions/remove-device.d.ts +11 -0
  66. package/src/lib/actions/remove-device.js +37 -0
  67. package/src/lib/actions/remove-device.js.map +1 -0
  68. package/src/lib/actions/remove-members-from-group.d.ts +12 -0
  69. package/src/lib/actions/remove-members-from-group.js +45 -0
  70. package/src/lib/actions/remove-members-from-group.js.map +1 -0
  71. package/src/lib/actions/remove-reaction.d.ts +13 -0
  72. package/src/lib/actions/remove-reaction.js +52 -0
  73. package/src/lib/actions/remove-reaction.js.map +1 -0
  74. package/src/lib/actions/request-approval-message.d.ts +15 -0
  75. package/src/lib/actions/request-approval-message.js +184 -0
  76. package/src/lib/actions/request-approval-message.js.map +1 -0
  77. package/src/lib/actions/resume-approval-flow.d.ts +11 -0
  78. package/src/lib/actions/resume-approval-flow.js +181 -0
  79. package/src/lib/actions/resume-approval-flow.js.map +1 -0
  80. package/src/lib/actions/search-numbers.d.ts +11 -0
  81. package/src/lib/actions/search-numbers.js +42 -0
  82. package/src/lib/actions/search-numbers.js.map +1 -0
  83. package/src/lib/actions/send-message.d.ts +27 -0
  84. package/src/lib/actions/send-message.js +176 -0
  85. package/src/lib/actions/send-message.js.map +1 -0
  86. package/src/lib/actions/send-reaction.d.ts +14 -0
  87. package/src/lib/actions/send-reaction.js +58 -0
  88. package/src/lib/actions/send-reaction.js.map +1 -0
  89. package/src/lib/actions/send-receipt.d.ts +13 -0
  90. package/src/lib/actions/send-receipt.js +58 -0
  91. package/src/lib/actions/send-receipt.js.map +1 -0
  92. package/src/lib/actions/start-typing.d.ts +11 -0
  93. package/src/lib/actions/start-typing.js +40 -0
  94. package/src/lib/actions/start-typing.js.map +1 -0
  95. package/src/lib/actions/stop-typing.d.ts +11 -0
  96. package/src/lib/actions/stop-typing.js +40 -0
  97. package/src/lib/actions/stop-typing.js.map +1 -0
  98. package/src/lib/actions/sync-contacts.d.ts +10 -0
  99. package/src/lib/actions/sync-contacts.js +32 -0
  100. package/src/lib/actions/sync-contacts.js.map +1 -0
  101. package/src/lib/actions/update-account-settings.d.ts +12 -0
  102. package/src/lib/actions/update-account-settings.js +49 -0
  103. package/src/lib/actions/update-account-settings.js.map +1 -0
  104. package/src/lib/actions/update-contact.d.ts +13 -0
  105. package/src/lib/actions/update-contact.js +56 -0
  106. package/src/lib/actions/update-contact.js.map +1 -0
  107. package/src/lib/actions/update-group.d.ts +19 -0
  108. package/src/lib/actions/update-group.js +125 -0
  109. package/src/lib/actions/update-group.js.map +1 -0
  110. package/src/lib/actions/update-profile.d.ts +13 -0
  111. package/src/lib/actions/update-profile.js +56 -0
  112. package/src/lib/actions/update-profile.js.map +1 -0
  113. package/src/lib/common/api-client.d.ts +24 -0
  114. package/src/lib/common/api-client.js +103 -0
  115. package/src/lib/common/api-client.js.map +1 -0
  116. package/src/lib/common/auth.d.ts +8 -0
  117. package/src/lib/common/auth.js +68 -0
  118. package/src/lib/common/auth.js.map +1 -0
  119. package/src/lib/common/message-utils.d.ts +81 -0
  120. package/src/lib/common/message-utils.js +327 -0
  121. package/src/lib/common/message-utils.js.map +1 -0
  122. package/src/lib/common/types.d.ts +65 -0
  123. package/src/lib/common/types.js +3 -0
  124. package/src/lib/common/types.js.map +1 -0
  125. package/src/lib/common/utils.d.ts +23 -0
  126. package/src/lib/common/utils.js +105 -0
  127. package/src/lib/common/utils.js.map +1 -0
  128. package/src/lib/triggers/new-group-member.d.ts +50 -0
  129. package/src/lib/triggers/new-group-member.js +155 -0
  130. package/src/lib/triggers/new-group-member.js.map +1 -0
  131. package/src/lib/triggers/new-message-received.d.ts +58 -0
  132. package/src/lib/triggers/new-message-received.js +469 -0
  133. package/src/lib/triggers/new-message-received.js.map +1 -0
  134. package/project.json +0 -58
  135. package/src/index.ts +0 -87
  136. package/src/lib/actions/add-admins-to-group.ts +0 -50
  137. package/src/lib/actions/add-device.ts +0 -45
  138. package/src/lib/actions/add-members-to-group.ts +0 -50
  139. package/src/lib/actions/block-group.ts +0 -36
  140. package/src/lib/actions/create-group.ts +0 -139
  141. package/src/lib/actions/delete-group.ts +0 -36
  142. package/src/lib/actions/get-contact.ts +0 -42
  143. package/src/lib/actions/get-group.ts +0 -37
  144. package/src/lib/actions/get-qr-code-link.ts +0 -62
  145. package/src/lib/actions/join-group.ts +0 -36
  146. package/src/lib/actions/list-accounts.ts +0 -20
  147. package/src/lib/actions/list-attachments.ts +0 -20
  148. package/src/lib/actions/list-contacts.ts +0 -37
  149. package/src/lib/actions/list-devices.ts +0 -38
  150. package/src/lib/actions/list-groups.ts +0 -32
  151. package/src/lib/actions/list-identities.ts +0 -32
  152. package/src/lib/actions/quit-group.ts +0 -36
  153. package/src/lib/actions/receive-messages.ts +0 -108
  154. package/src/lib/actions/remote-delete-message.ts +0 -56
  155. package/src/lib/actions/remove-admins-from-group.ts +0 -50
  156. package/src/lib/actions/remove-device.ts +0 -36
  157. package/src/lib/actions/remove-members-from-group.ts +0 -50
  158. package/src/lib/actions/remove-reaction.ts +0 -59
  159. package/src/lib/actions/request-approval-message.ts +0 -215
  160. package/src/lib/actions/search-numbers.ts +0 -47
  161. package/src/lib/actions/send-message.ts +0 -189
  162. package/src/lib/actions/send-reaction.ts +0 -66
  163. package/src/lib/actions/send-receipt.ts +0 -65
  164. package/src/lib/actions/start-typing.ts +0 -45
  165. package/src/lib/actions/stop-typing.ts +0 -45
  166. package/src/lib/actions/sync-contacts.ts +0 -31
  167. package/src/lib/actions/update-account-settings.ts +0 -57
  168. package/src/lib/actions/update-contact.ts +0 -65
  169. package/src/lib/actions/update-group.ts +0 -145
  170. package/src/lib/actions/update-profile.ts +0 -65
  171. package/src/lib/common/api-client.ts +0 -150
  172. package/src/lib/common/auth.ts +0 -66
  173. package/src/lib/common/message-utils.ts +0 -449
  174. package/src/lib/common/types.ts +0 -73
  175. package/src/lib/common/utils.ts +0 -106
  176. package/src/lib/triggers/new-group-member.ts +0 -176
  177. package/src/lib/triggers/new-message-received.ts +0 -618
  178. package/tsconfig.json +0 -19
  179. package/tsconfig.lib.json +0 -11
@@ -1,618 +0,0 @@
1
- import {
2
- createTrigger,
3
- TriggerStrategy,
4
- Property,
5
- AppConnectionValueForAuthProperty,
6
- StoreScope,
7
- } from '@activepieces/pieces-framework';
8
- import {
9
- DedupeStrategy,
10
- Polling,
11
- pollingHelper,
12
- HttpMethod,
13
- httpClient,
14
- } from '@activepieces/pieces-common';
15
- import { signalCliRestApiAuth } from '../common/auth';
16
- import { formatPhoneNumber } from '../common/utils';
17
- import WebSocket from 'ws';
18
-
19
- interface SignalMessage {
20
- envelope: {
21
- source: string;
22
- sourceNumber?: string;
23
- sourceUuid?: string;
24
- sourceName?: string;
25
- sourceDevice: number;
26
- timestamp: number;
27
- timestampISO?: string;
28
- dataMessage?: {
29
- message?: string;
30
- timestamp: number;
31
- expiresInSeconds?: number;
32
- attachments?: Array<{
33
- id: string;
34
- contentType: string;
35
- size: number;
36
- fileName?: string;
37
- width?: number;
38
- height?: number;
39
- voiceNote?: boolean;
40
- caption?: string;
41
- }>;
42
- mentions?: Array<{
43
- start: number;
44
- length: number;
45
- recipient: string;
46
- }>;
47
- groupInfo?: {
48
- groupId: string;
49
- type: string;
50
- members?: string[];
51
- name?: string;
52
- avatarId?: number;
53
- };
54
- quote?: {
55
- id: number;
56
- author: string;
57
- text?: string;
58
- };
59
- preview?: Array<{
60
- url: string;
61
- title: string;
62
- description?: string;
63
- }>;
64
- sticker?: {
65
- packId: string;
66
- stickerId: number;
67
- };
68
- reaction?: {
69
- emoji: string;
70
- targetAuthor: string;
71
- targetTimestamp: number;
72
- };
73
- viewOnce?: boolean;
74
- };
75
- syncMessage?: {
76
- sentMessage?: {
77
- destination: string;
78
- timestamp: number;
79
- message?: string;
80
- };
81
- };
82
- receipt?: {
83
- type: number;
84
- timestamp: number;
85
- timestamps: number[];
86
- };
87
- typing?: {
88
- action: number;
89
- timestamp: number;
90
- };
91
- };
92
- account: string;
93
- }
94
-
95
- interface ApprovalMapping {
96
- flowRunId: string;
97
- requestId: string;
98
- approveEmoji: string;
99
- disapproveEmoji: string;
100
- targetAuthor: string;
101
- messageTimestamp: number;
102
- timeoutSeconds: number;
103
- createdAt: number;
104
- }
105
-
106
- // Function to automatically resume approval flows
107
- async function tryResumeApprovalFlow(
108
- message: SignalMessage,
109
- store: any,
110
- apiUrl: string
111
- ): Promise<{ resumed: boolean; action?: string }> {
112
- console.log('[NewMessageReceived] DEBUG - Processing message:', {
113
- hasReaction: !!message.envelope?.dataMessage?.reaction,
114
- });
115
-
116
- // Check if it's a reaction
117
- if (!message.envelope?.dataMessage?.reaction) {
118
- return { resumed: false };
119
- }
120
-
121
- console.log('[NewMessageReceived] DEBUG - Reaction detected');
122
- const reaction = message.envelope.dataMessage.reaction;
123
- // Convert targetTimestamp from milliseconds to seconds (Unix timestamp)
124
- // Note: targetTimestamp in SignalMessage interface might be targetSentTimestamp in actual data
125
- const targetTimestampMs = (reaction as any).targetSentTimestamp || reaction.targetTimestamp;
126
- const targetTimestamp = Math.floor(targetTimestampMs / 1000);
127
- const targetAuthor = reaction.targetAuthor;
128
- const reactionEmoji = reaction.emoji;
129
-
130
- console.log('[NewMessageReceived] DEBUG - Reaction data:', {
131
- targetSentTimestampOriginal: targetTimestampMs,
132
- targetTimestamp,
133
- targetAuthor,
134
- reactionEmoji,
135
- });
136
-
137
- // Cleanup expired approvals
138
- const keysListKey = 'approval:keys';
139
- const existingKeys = (await store.get<string[]>(keysListKey, StoreScope.PROJECT)) || [];
140
- const currentTimestamp = Math.floor(Date.now() / 1000);
141
- const validKeys: string[] = [];
142
- const keysToDelete: string[] = [];
143
-
144
- console.log('[NewMessageReceived] DEBUG - Store info:', {
145
- existingKeysCount: existingKeys.length,
146
- existingKeys: existingKeys,
147
- currentTimestamp,
148
- });
149
-
150
- for (const key of existingKeys) {
151
- const mapping = await store.get<ApprovalMapping>(key, StoreScope.PROJECT);
152
- if (mapping) {
153
- // Check if expired
154
- if (currentTimestamp - mapping.createdAt > mapping.timeoutSeconds) {
155
- // Expired - delete it and flowRunId mapping
156
- await store.delete(key, StoreScope.PROJECT);
157
- const flowRunMappingKey = `approval:flowRun:${mapping.flowRunId}`;
158
- await store.delete(flowRunMappingKey, StoreScope.PROJECT);
159
- keysToDelete.push(key);
160
- } else {
161
- validKeys.push(key);
162
- }
163
- } else {
164
- // Mapping not found - remove from list
165
- keysToDelete.push(key);
166
- }
167
- }
168
-
169
- // Update keys list if any were deleted
170
- if (keysToDelete.length > 0) {
171
- await store.put(keysListKey, validKeys, StoreScope.PROJECT);
172
- }
173
-
174
- console.log('[NewMessageReceived] DEBUG - Cleanup result:', {
175
- keysDeleted: keysToDelete.length,
176
- validKeysCount: validKeys.length,
177
- });
178
-
179
- // Look up the specific approval mapping
180
- const storeKey = `approval:${targetTimestamp}:${targetAuthor}`;
181
-
182
- console.log('[NewMessageReceived] DEBUG - Store lookup:', {
183
- storeKey,
184
- existingKeysCount: existingKeys.length,
185
- });
186
-
187
- const mapping = await store.get<ApprovalMapping>(storeKey, StoreScope.PROJECT);
188
-
189
- if (!mapping) {
190
- // Not an approval message
191
- console.log('[NewMessageReceived] DEBUG - No mapping found:', {
192
- reason: 'not_an_approval_message',
193
- searchedKey: storeKey,
194
- });
195
- return { resumed: false };
196
- }
197
-
198
- console.log('[NewMessageReceived] DEBUG - Mapping found:', {
199
- flowRunId: mapping.flowRunId,
200
- requestId: mapping.requestId,
201
- approveEmoji: mapping.approveEmoji,
202
- disapproveEmoji: mapping.disapproveEmoji,
203
- messageTimestamp: mapping.messageTimestamp,
204
- createdAt: mapping.createdAt,
205
- timeoutSeconds: mapping.timeoutSeconds,
206
- });
207
-
208
- // Check if expired
209
- const ageInSeconds = currentTimestamp - mapping.createdAt;
210
- const isExpired = ageInSeconds > mapping.timeoutSeconds;
211
-
212
- console.log('[NewMessageReceived] DEBUG - Expiration check:', {
213
- currentTimestamp,
214
- createdAt: mapping.createdAt,
215
- ageInSeconds,
216
- timeoutSeconds: mapping.timeoutSeconds,
217
- isExpired,
218
- });
219
-
220
- if (isExpired) {
221
- // Expired - delete and return
222
- await store.delete(storeKey, StoreScope.PROJECT);
223
- const flowRunMappingKey = `approval:flowRun:${mapping.flowRunId}`;
224
- await store.delete(flowRunMappingKey, StoreScope.PROJECT);
225
- const updatedKeys = validKeys.filter(key => key !== storeKey);
226
- await store.put(keysListKey, updatedKeys, StoreScope.PROJECT);
227
- console.log('[NewMessageReceived] DEBUG - Approval expired');
228
- return { resumed: false };
229
- }
230
-
231
- // Check emoji and determine action
232
- let action: string;
233
-
234
- console.log('[NewMessageReceived] DEBUG - Emoji check:', {
235
- receivedEmoji: reactionEmoji,
236
- expectedApproveEmoji: mapping.approveEmoji,
237
- expectedDisapproveEmoji: mapping.disapproveEmoji,
238
- });
239
-
240
- if (reactionEmoji === mapping.approveEmoji) {
241
- action = 'approve';
242
- console.log('[NewMessageReceived] DEBUG - Emoji matched: approve');
243
- } else if (reactionEmoji === mapping.disapproveEmoji) {
244
- action = 'disapprove';
245
- console.log('[NewMessageReceived] DEBUG - Emoji matched: disapprove');
246
- } else {
247
- // Invalid emoji - not an approval reaction
248
- console.log('[NewMessageReceived] DEBUG - Invalid emoji:', {
249
- reason: 'invalid_emoji',
250
- receivedEmoji: reactionEmoji,
251
- });
252
- return { resumed: false };
253
- }
254
-
255
- // Make HTTP request to resume the flow
256
- const resumeUrl = `${apiUrl}v1/flow-runs/${mapping.flowRunId}/requests/${mapping.requestId}?action=${action}`;
257
-
258
- console.log('[NewMessageReceived] DEBUG - Attempting resume:', {
259
- resumeUrl,
260
- apiUrl,
261
- flowRunId: mapping.flowRunId,
262
- requestId: mapping.requestId,
263
- action,
264
- });
265
-
266
- try {
267
- const response = await httpClient.sendRequest({
268
- method: HttpMethod.POST,
269
- url: resumeUrl,
270
- headers: {
271
- 'Content-Type': 'application/json',
272
- },
273
- });
274
-
275
- console.log('[NewMessageReceived] DEBUG - Resume successful:', {
276
- flowRunId: mapping.flowRunId,
277
- action,
278
- responseStatus: response.status,
279
- responseBody: response.body,
280
- });
281
-
282
- // Delete mapping from Store (cleanup)
283
- await store.delete(storeKey, StoreScope.PROJECT);
284
-
285
- // Delete flowRunId mapping
286
- const flowRunMappingKey = `approval:flowRun:${mapping.flowRunId}`;
287
- await store.delete(flowRunMappingKey, StoreScope.PROJECT);
288
-
289
- // Remove key from approval keys list
290
- const finalKeys = validKeys.filter(key => key !== storeKey);
291
- await store.put(keysListKey, finalKeys, StoreScope.PROJECT);
292
-
293
- console.log('[NewMessageReceived] DEBUG - Cleanup completed');
294
-
295
- return { resumed: true, action };
296
- } catch (error) {
297
- // If resume fails, log but don't throw - message will still be returned
298
- console.error('[NewMessageReceived] DEBUG - Resume failed:', {
299
- error: error instanceof Error ? error.message : String(error),
300
- errorStack: error instanceof Error ? error.stack : undefined,
301
- resumeUrl,
302
- flowRunId: mapping.flowRunId,
303
- reason: 'resume_failed',
304
- });
305
- return { resumed: false };
306
- }
307
- }
308
-
309
- const polling: Polling<
310
- AppConnectionValueForAuthProperty<typeof signalCliRestApiAuth>,
311
- {
312
- number: string;
313
- timeout?: number;
314
- ignore_attachments?: boolean;
315
- ignore_stories?: boolean;
316
- max_messages?: number;
317
- send_read_receipts?: boolean;
318
- }
319
- > = {
320
- strategy: DedupeStrategy.TIMEBASED,
321
- items: async ({ auth, propsValue, lastFetchEpochMS }) => {
322
- const { baseUrl, useBasicAuth, basicAuthUsername, basicAuthPassword, mode = 'normal' } = auth.props;
323
- const { number, timeout = 1, ignore_attachments = false, ignore_stories = false, max_messages, send_read_receipts = false } = propsValue;
324
-
325
- const formattedNumber = formatPhoneNumber(number);
326
-
327
- // Build query parameters
328
- const queryParams = new URLSearchParams();
329
- queryParams.append('timeout', timeout.toString());
330
- queryParams.append('ignore_attachments', ignore_attachments.toString());
331
- queryParams.append('ignore_stories', ignore_stories.toString());
332
- if (max_messages) {
333
- queryParams.append('max_messages', max_messages.toString());
334
- }
335
- queryParams.append('send_read_receipts', send_read_receipts.toString());
336
-
337
- const baseUrlClean = baseUrl.replace(/\/$/, '');
338
- const httpUrl = `${baseUrlClean}/v1/receive/${encodeURIComponent(formattedNumber)}?${queryParams.toString()}`;
339
-
340
- // Build headers
341
- const headers: Record<string, string> = {};
342
-
343
- // Add Basic Auth header if configured
344
- if (useBasicAuth && basicAuthUsername && basicAuthPassword) {
345
- const credentials = Buffer.from(
346
- `${basicAuthUsername}:${basicAuthPassword}`
347
- ).toString('base64');
348
- headers['Authorization'] = `Basic ${credentials}`;
349
- }
350
-
351
- // Use the configured mode to determine which method to use
352
- if (mode === 'json-rpc') {
353
- // Use WebSocket for json-rpc mode
354
- return tryWebSocketReceive(httpUrl, headers, timeout, max_messages);
355
- } else {
356
- // Use HTTP GET for normal/native mode
357
- return tryHttpReceive(httpUrl, headers);
358
- }
359
- },
360
- };
361
-
362
- // WebSocket receive function (for json-rpc mode)
363
- async function tryWebSocketReceive(
364
- httpUrl: string,
365
- headers: Record<string, string>,
366
- timeout: number,
367
- max_messages?: number
368
- ): Promise<Array<{ epochMilliSeconds: number; data: SignalMessage }>> {
369
- const wsUrl = httpUrl.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:');
370
- const wsHeaders: Record<string, string> = {
371
- ...headers,
372
- 'Connection': 'Upgrade',
373
- 'Upgrade': 'websocket',
374
- };
375
-
376
- return new Promise((resolve, reject) => {
377
- const messages: SignalMessage[] = [];
378
- let messageCount = 0;
379
- const maxMessagesToCollect = max_messages || Infinity;
380
- const timeoutMs = timeout * 1000;
381
- let resolved = false;
382
-
383
- const resolveOnce = (result: Array<{ epochMilliSeconds: number; data: SignalMessage }>) => {
384
- if (!resolved) {
385
- resolved = true;
386
- resolve(result);
387
- }
388
- };
389
-
390
- const rejectOnce = (error: Error) => {
391
- if (!resolved) {
392
- resolved = true;
393
- reject(error);
394
- }
395
- };
396
-
397
- const processMessages = () => {
398
- // Filter messages that have dataMessage (actual message content)
399
- const dataMessages = messages.filter((msg) => msg.envelope?.dataMessage);
400
-
401
- // Map to polling format with timestamp
402
- return dataMessages.map((message) => {
403
- const timestamp = message.envelope.dataMessage?.timestamp || message.envelope.timestamp || Date.now();
404
- return {
405
- epochMilliSeconds: timestamp * 1000, // Convert to milliseconds
406
- data: message,
407
- };
408
- });
409
- };
410
-
411
- const ws = new WebSocket(wsUrl, {
412
- headers: wsHeaders,
413
- });
414
-
415
- const timeoutId = setTimeout(() => {
416
- if (!resolved) {
417
- ws.close();
418
- resolveOnce(processMessages());
419
- }
420
- }, timeoutMs);
421
-
422
- ws.on('open', () => {
423
- // WebSocket connection opened successfully
424
- // The server will send messages as they arrive
425
- });
426
-
427
- ws.on('message', (data: WebSocket.Data) => {
428
- try {
429
- const messageText = data.toString();
430
-
431
- // Check if it's an error message
432
- if (messageText.includes('"error"') || messageText.includes('"Msg"')) {
433
- try {
434
- const errorObj = JSON.parse(messageText);
435
- if (errorObj.error || errorObj.Msg) {
436
- clearTimeout(timeoutId);
437
- ws.close();
438
- // If it's a "no messages" type error, return empty array
439
- if (errorObj.Msg && errorObj.Msg.includes('No new messages')) {
440
- resolveOnce([]);
441
- } else {
442
- rejectOnce(new Error(errorObj.error || errorObj.Msg));
443
- }
444
- return;
445
- }
446
- } catch {
447
- // Not a JSON error, continue processing
448
- }
449
- }
450
-
451
- // Try to parse as JSON message
452
- try {
453
- const message: SignalMessage = JSON.parse(messageText);
454
- messages.push(message);
455
- messageCount++;
456
-
457
- // If we've reached max_messages, close the connection
458
- if (messageCount >= maxMessagesToCollect) {
459
- clearTimeout(timeoutId);
460
- ws.close();
461
- resolveOnce(processMessages());
462
- }
463
- } catch (parseError) {
464
- // If parsing fails, ignore this message
465
- // The server might send non-JSON data
466
- }
467
- } catch (error) {
468
- // Ignore individual message errors
469
- }
470
- });
471
-
472
- ws.on('error', (error) => {
473
- clearTimeout(timeoutId);
474
- ws.close();
475
- // Reject to trigger fallback to HTTP GET
476
- rejectOnce(error);
477
- });
478
-
479
- ws.on('close', () => {
480
- clearTimeout(timeoutId);
481
- // If we haven't resolved yet, resolve with collected messages
482
- if (!resolved) {
483
- resolveOnce(processMessages());
484
- }
485
- });
486
- });
487
- }
488
-
489
- // HTTP GET receive function (for normal/native mode)
490
- async function tryHttpReceive(
491
- httpUrl: string,
492
- headers: Record<string, string>
493
- ): Promise<Array<{ epochMilliSeconds: number; data: SignalMessage }>> {
494
- try {
495
- const response = await httpClient.sendRequest<SignalMessage[] | string>({
496
- method: HttpMethod.GET,
497
- url: httpUrl,
498
- headers,
499
- });
500
-
501
- // The API returns either a JSON array of messages or a JSON string
502
- let messages: SignalMessage[] = [];
503
- if (typeof response.body === 'string') {
504
- try {
505
- messages = JSON.parse(response.body);
506
- } catch {
507
- // If parsing fails, try to parse as array
508
- messages = [];
509
- }
510
- } else if (Array.isArray(response.body)) {
511
- messages = response.body;
512
- } else {
513
- messages = [];
514
- }
515
-
516
- // Filter messages that have dataMessage (actual message content)
517
- const dataMessages = messages.filter((msg) => msg.envelope?.dataMessage);
518
-
519
- // Map to polling format with timestamp
520
- return dataMessages.map((message) => {
521
- const timestamp = message.envelope.dataMessage?.timestamp || message.envelope.timestamp || Date.now();
522
- return {
523
- epochMilliSeconds: timestamp * 1000, // Convert to milliseconds
524
- data: message,
525
- };
526
- });
527
- } catch (error) {
528
- // If no messages are available, return empty array
529
- if (error instanceof Error && error.message.includes('No new messages')) {
530
- return [];
531
- }
532
- throw error;
533
- }
534
- }
535
-
536
- export const newMessageReceived = createTrigger({
537
- auth: signalCliRestApiAuth,
538
- name: 'newMessageReceived',
539
- displayName: 'New Message Received',
540
- description: 'Triggers when a new message is received via Signal. Automatically resumes approval flows if the message is a reaction to an approval request.',
541
- type: TriggerStrategy.POLLING,
542
- props: {
543
- number: Property.ShortText({
544
- displayName: 'Phone Number',
545
- description: 'Registered phone number in international format (e.g., +43123456789)',
546
- required: true,
547
- }),
548
- timeout: Property.Number({
549
- displayName: 'Timeout (seconds)',
550
- description: 'Receive timeout in seconds (default: 1)',
551
- required: false,
552
- defaultValue: 1,
553
- }),
554
- ignore_attachments: Property.Checkbox({
555
- displayName: 'Ignore Attachments',
556
- description: 'Ignore attachments when receiving messages',
557
- required: false,
558
- defaultValue: false,
559
- }),
560
- ignore_stories: Property.Checkbox({
561
- displayName: 'Ignore Stories',
562
- description: 'Ignore stories when receiving messages',
563
- required: false,
564
- defaultValue: false,
565
- }),
566
- max_messages: Property.Number({
567
- displayName: 'Max Messages',
568
- description: 'Maximum number of messages to receive (default: unlimited)',
569
- required: false,
570
- }),
571
- send_read_receipts: Property.Checkbox({
572
- displayName: 'Send Read Receipts',
573
- description: 'Automatically send read receipts when receiving messages',
574
- required: false,
575
- defaultValue: false,
576
- }),
577
- },
578
- sampleData: {
579
- envelope: {
580
- source: '+43123456789',
581
- sourceNumber: '+43123456789',
582
- sourceDevice: 1,
583
- timestamp: 1234567890,
584
- dataMessage: {
585
- message: 'Hello, this is a test message',
586
- timestamp: 1234567890,
587
- },
588
- },
589
- account: '+43123456789',
590
- },
591
- async test(context) {
592
- return await pollingHelper.test(polling, context);
593
- },
594
- async onEnable(context) {
595
- await pollingHelper.onEnable(polling, context);
596
- },
597
- async onDisable(context) {
598
- await pollingHelper.onDisable(polling, context);
599
- },
600
- async run(context) {
601
- // Get messages from polling
602
- const messages = await pollingHelper.poll(polling, context);
603
-
604
- // Process each message: try to resume approval flows if applicable
605
- // Messages are still returned regardless of whether they triggered a resume
606
- // Debug information is output via console.log (visible in Docker logs)
607
- const apiUrl = context.server?.apiUrl || '';
608
-
609
- for (const message of messages) {
610
- const signalMessage = message as SignalMessage;
611
- // This will output debug info via console.log
612
- await tryResumeApprovalFlow(signalMessage, context.store, apiUrl);
613
- }
614
-
615
- // Return messages without debug fields (normal output)
616
- return messages;
617
- },
618
- });
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "extends": "../../../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "module": "commonjs",
5
- "forceConsistentCasingInFileNames": true,
6
- "strict": true,
7
- "noImplicitOverride": true,
8
- "noPropertyAccessFromIndexSignature": true,
9
- "noImplicitReturns": true,
10
- "noFallthroughCasesInSwitch": true
11
- },
12
- "files": [],
13
- "include": [],
14
- "references": [
15
- {
16
- "path": "./tsconfig.lib.json"
17
- }
18
- ]
19
- }
package/tsconfig.lib.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "module": "commonjs",
5
- "outDir": "../../../../dist/out-tsc",
6
- "declaration": true,
7
- "types": ["node"]
8
- },
9
- "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
10
- "include": ["src/**/*.ts", "src/lib/actions/common/utils.ts"]
11
- }