signal-sdk 0.0.9 → 0.1.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 (44) hide show
  1. package/README.md +184 -61
  2. package/dist/MultiAccountManager.d.ts +149 -0
  3. package/dist/MultiAccountManager.js +320 -0
  4. package/dist/SignalBot.d.ts +1 -0
  5. package/dist/SignalBot.js +20 -2
  6. package/dist/SignalCli.d.ts +315 -16
  7. package/dist/SignalCli.js +880 -26
  8. package/dist/__tests__/MultiAccountManager.test.d.ts +4 -0
  9. package/dist/__tests__/MultiAccountManager.test.js +209 -0
  10. package/dist/__tests__/SignalBot.additional.test.d.ts +5 -0
  11. package/dist/__tests__/SignalBot.additional.test.js +353 -0
  12. package/dist/__tests__/SignalBot.test.js +5 -0
  13. package/dist/__tests__/SignalCli.advanced.test.d.ts +5 -0
  14. package/dist/__tests__/SignalCli.advanced.test.js +295 -0
  15. package/dist/__tests__/SignalCli.e2e.test.d.ts +5 -0
  16. package/dist/__tests__/SignalCli.e2e.test.js +240 -0
  17. package/dist/__tests__/SignalCli.integration.test.d.ts +5 -0
  18. package/dist/__tests__/SignalCli.integration.test.js +225 -0
  19. package/dist/__tests__/SignalCli.methods.test.d.ts +5 -0
  20. package/dist/__tests__/SignalCli.methods.test.js +556 -0
  21. package/dist/__tests__/SignalCli.parsing.test.d.ts +5 -0
  22. package/dist/__tests__/SignalCli.parsing.test.js +258 -0
  23. package/dist/__tests__/SignalCli.test.js +249 -13
  24. package/dist/__tests__/config.test.d.ts +5 -0
  25. package/dist/__tests__/config.test.js +252 -0
  26. package/dist/__tests__/errors.test.d.ts +5 -0
  27. package/dist/__tests__/errors.test.js +276 -0
  28. package/dist/__tests__/retry.test.d.ts +4 -0
  29. package/dist/__tests__/retry.test.js +123 -0
  30. package/dist/__tests__/validators.test.d.ts +4 -0
  31. package/dist/__tests__/validators.test.js +147 -0
  32. package/dist/config.d.ts +82 -0
  33. package/dist/config.js +116 -0
  34. package/dist/errors.d.ts +32 -0
  35. package/dist/errors.js +75 -0
  36. package/dist/index.d.ts +5 -0
  37. package/dist/index.js +7 -1
  38. package/dist/interfaces.d.ts +200 -10
  39. package/dist/interfaces.js +1 -1
  40. package/dist/retry.d.ts +56 -0
  41. package/dist/retry.js +152 -0
  42. package/dist/validators.d.ts +59 -0
  43. package/dist/validators.js +170 -0
  44. package/package.json +1 -1
@@ -5,7 +5,7 @@
5
5
  * which uses JSON-RPC communication with signal-cli for optimal performance.
6
6
  *
7
7
  * @author Signal SDK Team
8
- * @version 2.0.0
8
+ * @version 0.1.0
9
9
  */
10
10
  /**
11
11
  * @deprecated This interface is no longer used since switching to JSON-RPC format.
@@ -278,6 +278,8 @@ export interface SendResponse {
278
278
  export interface GroupInfo {
279
279
  /** Base64 encoded group ID */
280
280
  groupId: string;
281
+ /** Alias for groupId */
282
+ id?: string;
281
283
  /** Group display name */
282
284
  name: string;
283
285
  /** Group description */
@@ -306,17 +308,23 @@ export interface GroupInfo {
306
308
  permissionSendMessage: string;
307
309
  /** Group invite link */
308
310
  groupInviteLink?: string;
311
+ /** Alias for groupInviteLink */
312
+ inviteLink?: string;
309
313
  }
310
314
  /**
311
315
  * Represents a received message.
312
316
  */
313
317
  export interface Message {
314
- id: string;
318
+ id?: string;
315
319
  source: string;
320
+ sourceUuid?: string;
321
+ sourceDevice?: number;
316
322
  text?: string;
317
323
  timestamp: number;
318
324
  attachments?: Attachment[];
319
325
  reactions?: Reaction[];
326
+ reaction?: any;
327
+ groupId?: string;
320
328
  groupInfo?: {
321
329
  id: string;
322
330
  name?: string;
@@ -333,8 +341,12 @@ export interface Message {
333
341
  textStyles?: TextStyle[];
334
342
  expiresInSeconds?: number;
335
343
  isViewOnce?: boolean;
344
+ viewOnce?: boolean;
336
345
  remoteDelete?: boolean;
337
346
  isExpirationUpdate?: boolean;
347
+ syncMessage?: any;
348
+ receipt?: any;
349
+ typing?: any;
338
350
  }
339
351
  /**
340
352
  * Represents a mention in a message.
@@ -343,6 +355,7 @@ export interface Mention {
343
355
  start: number;
344
356
  length: number;
345
357
  number: string;
358
+ recipient?: string;
346
359
  name?: string;
347
360
  }
348
361
  /**
@@ -379,11 +392,23 @@ export interface Contact {
379
392
  uuid?: string;
380
393
  blocked: boolean;
381
394
  profileName?: string;
395
+ /** Given name (first name) from profile */
396
+ givenName?: string;
397
+ /** Family name (last name) from profile */
398
+ familyName?: string;
399
+ /** MobileCoin address for payments */
400
+ mobileCoinAddress?: string;
382
401
  profileAvatar?: string;
383
402
  color?: string;
384
403
  archived?: boolean;
385
404
  mutedUntil?: number;
386
405
  hideStory?: boolean;
406
+ /** Profile key for encrypted profile access */
407
+ profileKey?: string;
408
+ /** Contact's username */
409
+ username?: string;
410
+ /** Whether this contact is a registered Signal user */
411
+ registered?: boolean;
387
412
  }
388
413
  /**
389
414
  * Represents a Signal group.
@@ -393,6 +418,14 @@ export interface Group {
393
418
  name: string;
394
419
  members: string[];
395
420
  admins?: string[];
421
+ /** Pending members awaiting invite acceptance */
422
+ pendingMembers?: string[];
423
+ /** Banned members who cannot rejoin */
424
+ bannedMembers?: string[];
425
+ /** Group invite link for joining */
426
+ inviteLink?: string;
427
+ /** Whether invite link approval is required */
428
+ inviteLinkRequiresApproval?: boolean;
396
429
  isBlocked: boolean;
397
430
  isMember: boolean;
398
431
  isAdmin?: boolean;
@@ -401,12 +434,15 @@ export interface Group {
401
434
  color?: string;
402
435
  archived?: boolean;
403
436
  mutedUntil?: number;
404
- inviteLink?: string;
405
437
  permissionAddMember?: 'EVERY_MEMBER' | 'ONLY_ADMINS';
406
438
  permissionEditDetails?: 'EVERY_MEMBER' | 'ONLY_ADMINS';
407
439
  permissionSendMessage?: 'EVERY_MEMBER' | 'ONLY_ADMINS';
408
440
  announcementsOnly?: boolean;
409
441
  expirationTimer?: number;
442
+ /** Group version (v1 or v2) */
443
+ version?: number;
444
+ /** Group master key for v2 groups */
445
+ masterKey?: string;
410
446
  }
411
447
  /**
412
448
  * Options for updating a Signal group.
@@ -469,15 +505,18 @@ export interface SendMessageOptions {
469
505
  text?: string;
470
506
  attachments?: Attachment[];
471
507
  mentions?: Mention[];
508
+ textStyles?: TextStyle[];
472
509
  };
473
510
  sticker?: Sticker;
474
511
  expiresInSeconds?: number;
475
512
  isViewOnce?: boolean;
476
513
  linkPreview?: boolean;
477
- editMessage?: {
478
- timestamp: number;
479
- dataMessage: any;
480
- };
514
+ previewUrl?: string;
515
+ editTimestamp?: number;
516
+ storyTimestamp?: number;
517
+ storyAuthor?: string;
518
+ noteToSelf?: boolean;
519
+ endSession?: boolean;
481
520
  }
482
521
  /**
483
522
  * Represents a user profile.
@@ -583,9 +622,10 @@ export interface PinConfiguration {
583
622
  export interface IdentityKey {
584
623
  number: string;
585
624
  identityKey: string;
586
- trustLevel: 'TRUSTED_UNVERIFIED' | 'TRUSTED_VERIFIED' | 'UNTRUSTED';
587
- addedDate: number;
588
- firstUse: boolean;
625
+ safetyNumber?: string;
626
+ trustLevel?: 'TRUSTED_UNVERIFIED' | 'TRUSTED_VERIFIED' | 'UNTRUSTED' | 'TRUST_ON_FIRST_USE';
627
+ addedDate?: number;
628
+ firstUse?: boolean;
589
629
  }
590
630
  /**
591
631
  * Represents a user status (registered/unregistered).
@@ -936,3 +976,153 @@ export interface UploadProgress {
936
976
  /** Estimated time remaining in seconds */
937
977
  timeRemaining?: number;
938
978
  }
979
+ /**
980
+ * Options for creating a poll
981
+ */
982
+ export interface PollCreateOptions {
983
+ /** The poll question */
984
+ question: string;
985
+ /** Array of poll options */
986
+ options: string[];
987
+ /** Allow multiple selections (default: true) */
988
+ multiSelect?: boolean;
989
+ /** Recipients to send the poll to */
990
+ recipients?: string[];
991
+ /** Group ID to send the poll to */
992
+ groupId?: string;
993
+ }
994
+ /**
995
+ * Options for voting on a poll
996
+ */
997
+ export interface PollVoteOptions {
998
+ /** Author of the poll */
999
+ pollAuthor: string;
1000
+ /** Timestamp of the poll message */
1001
+ pollTimestamp: number;
1002
+ /** Array of option indexes to vote for */
1003
+ optionIndexes: number[];
1004
+ /** Vote count (increase for each vote) */
1005
+ voteCount?: number;
1006
+ }
1007
+ /**
1008
+ * Options for terminating a poll
1009
+ */
1010
+ export interface PollTerminateOptions {
1011
+ /** Timestamp of the poll message to terminate */
1012
+ pollTimestamp: number;
1013
+ }
1014
+ /**
1015
+ * Options for sending a story
1016
+ */
1017
+ export interface StoryOptions {
1018
+ /** Story content (text or attachment path) */
1019
+ content?: string;
1020
+ /** Attachment for the story */
1021
+ attachment?: string;
1022
+ /** Text attachment with style */
1023
+ textAttachment?: {
1024
+ text: string;
1025
+ textStyle?: 'DEFAULT' | 'REGULAR' | 'BOLD' | 'SERIF' | 'SCRIPT' | 'CONDENSED';
1026
+ textForegroundColor?: string;
1027
+ textBackgroundColor?: string;
1028
+ preview?: {
1029
+ url: string;
1030
+ title?: string;
1031
+ description?: string;
1032
+ };
1033
+ };
1034
+ /** Allow replies (default: true) */
1035
+ allowReplies?: boolean;
1036
+ }
1037
+ /**
1038
+ * Options for getting attachment data
1039
+ */
1040
+ export interface GetAttachmentOptions {
1041
+ /** Attachment ID */
1042
+ id: string;
1043
+ /** Recipient who sent the attachment */
1044
+ recipient?: string;
1045
+ /** Group ID where attachment was sent */
1046
+ groupId?: string;
1047
+ }
1048
+ /**
1049
+ * Options for getting avatar data
1050
+ */
1051
+ export interface GetAvatarOptions {
1052
+ /** Contact number for contact avatar */
1053
+ contact?: string;
1054
+ /** Profile number for profile avatar */
1055
+ profile?: string;
1056
+ /** Group ID for group avatar */
1057
+ groupId?: string;
1058
+ }
1059
+ /**
1060
+ * Options for getting sticker data
1061
+ */
1062
+ export interface GetStickerOptions {
1063
+ /** Sticker pack ID (hex encoded) */
1064
+ packId: string;
1065
+ /** Sticker index in the pack */
1066
+ stickerId: number;
1067
+ }
1068
+ /**
1069
+ * Options for updating account information
1070
+ */
1071
+ export interface UpdateAccountOptions {
1072
+ /** New device name */
1073
+ deviceName?: string;
1074
+ /** Username to set (with or without discriminator) */
1075
+ username?: string;
1076
+ /** Delete the current username */
1077
+ deleteUsername?: boolean;
1078
+ /** Enable unrestricted unidentified sender */
1079
+ unrestrictedUnidentifiedSender?: boolean;
1080
+ /** Enable discoverability by phone number */
1081
+ discoverableByNumber?: boolean;
1082
+ /** Enable number sharing */
1083
+ numberSharing?: boolean;
1084
+ }
1085
+ /**
1086
+ * Result from account update with username
1087
+ */
1088
+ export interface AccountUpdateResult {
1089
+ /** Success status */
1090
+ success: boolean;
1091
+ /** New username with discriminator */
1092
+ username?: string;
1093
+ /** Username link URL */
1094
+ usernameLink?: string;
1095
+ /** Error message if failed */
1096
+ error?: string;
1097
+ }
1098
+ /**
1099
+ * Options for receiving messages
1100
+ */
1101
+ export interface ReceiveOptions {
1102
+ /** Timeout in seconds (default: 5) */
1103
+ timeout?: number;
1104
+ /** Maximum number of messages to receive (default: unlimited) */
1105
+ maxMessages?: number;
1106
+ /** Skip downloading attachments */
1107
+ ignoreAttachments?: boolean;
1108
+ /** Skip receiving stories */
1109
+ ignoreStories?: boolean;
1110
+ /** Send read receipts automatically */
1111
+ sendReadReceipts?: boolean;
1112
+ }
1113
+ /**
1114
+ * Options for sending contacts sync
1115
+ */
1116
+ export interface SendContactsOptions {
1117
+ /** Include all recipients, not just contacts */
1118
+ includeAllRecipients?: boolean;
1119
+ }
1120
+ /**
1121
+ * Options for listing groups
1122
+ */
1123
+ export interface ListGroupsOptions {
1124
+ /** Show detailed information */
1125
+ detailed?: boolean;
1126
+ /** Filter by specific group IDs */
1127
+ groupIds?: string[];
1128
+ }
@@ -6,6 +6,6 @@
6
6
  * which uses JSON-RPC communication with signal-cli for optimal performance.
7
7
  *
8
8
  * @author Signal SDK Team
9
- * @version 2.0.0
9
+ * @version 0.1.0
10
10
  */
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Retry utilities with exponential backoff
3
+ * Provides robust retry mechanisms for operations
4
+ */
5
+ export interface RetryOptions {
6
+ /** Maximum number of retry attempts */
7
+ maxAttempts?: number;
8
+ /** Initial delay in milliseconds */
9
+ initialDelay?: number;
10
+ /** Maximum delay in milliseconds */
11
+ maxDelay?: number;
12
+ /** Multiplier for exponential backoff */
13
+ backoffMultiplier?: number;
14
+ /** Timeout for each attempt in milliseconds */
15
+ timeout?: number;
16
+ /** Function to determine if error is retryable */
17
+ isRetryable?: (error: any) => boolean;
18
+ /** Callback for each retry attempt */
19
+ onRetry?: (attempt: number, error: any) => void;
20
+ }
21
+ /**
22
+ * Executes an operation with retry logic and exponential backoff
23
+ * @param operation Function to execute
24
+ * @param options Retry configuration options
25
+ * @returns Result of the operation
26
+ */
27
+ export declare function withRetry<T>(operation: () => Promise<T>, options?: RetryOptions): Promise<T>;
28
+ /**
29
+ * Executes an operation with a timeout
30
+ * @param promise Promise to execute
31
+ * @param timeoutMs Timeout in milliseconds
32
+ * @returns Result of the promise
33
+ */
34
+ export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T>;
35
+ /**
36
+ * Sleep for a specified duration
37
+ * @param ms Duration in milliseconds
38
+ */
39
+ export declare function sleep(ms: number): Promise<void>;
40
+ /**
41
+ * Rate limiter to prevent exceeding API limits
42
+ */
43
+ export declare class RateLimiter {
44
+ private maxConcurrent;
45
+ private minInterval;
46
+ private queue;
47
+ private activeRequests;
48
+ constructor(maxConcurrent?: number, minInterval?: number);
49
+ /**
50
+ * Execute an operation with rate limiting
51
+ * @param operation Function to execute
52
+ * @returns Result of the operation
53
+ */
54
+ execute<T>(operation: () => Promise<T>): Promise<T>;
55
+ private reserveSlot;
56
+ }
package/dist/retry.js ADDED
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ /**
3
+ * Retry utilities with exponential backoff
4
+ * Provides robust retry mechanisms for operations
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.RateLimiter = void 0;
8
+ exports.withRetry = withRetry;
9
+ exports.withTimeout = withTimeout;
10
+ exports.sleep = sleep;
11
+ const errors_1 = require("./errors");
12
+ const DEFAULT_RETRY_OPTIONS = {
13
+ maxAttempts: 3,
14
+ initialDelay: 1000,
15
+ maxDelay: 30000,
16
+ backoffMultiplier: 2,
17
+ timeout: 60000,
18
+ isRetryable: (error) => {
19
+ // Retry on connection errors, timeouts, and certain server errors
20
+ if (!error)
21
+ return false;
22
+ const errorMessage = error.message?.toLowerCase() || '';
23
+ const isConnectionError = errorMessage.includes('connection') ||
24
+ errorMessage.includes('timeout') ||
25
+ errorMessage.includes('econnrefused') ||
26
+ errorMessage.includes('econnreset');
27
+ const isServerError = error.code === 500 || error.code === 502 || error.code === 503;
28
+ // Don't retry on authentication or validation errors
29
+ const isClientError = error.code === 401 || error.code === 403 || error.code === 400;
30
+ return (isConnectionError || isServerError) && !isClientError;
31
+ },
32
+ onRetry: () => { }
33
+ };
34
+ /**
35
+ * Executes an operation with retry logic and exponential backoff
36
+ * @param operation Function to execute
37
+ * @param options Retry configuration options
38
+ * @returns Result of the operation
39
+ */
40
+ async function withRetry(operation, options = {}) {
41
+ const config = { ...DEFAULT_RETRY_OPTIONS, ...options };
42
+ let lastError;
43
+ for (let attempt = 1; attempt <= config.maxAttempts; attempt++) {
44
+ try {
45
+ // Execute with timeout
46
+ const result = await withTimeout(operation(), config.timeout);
47
+ return result;
48
+ }
49
+ catch (error) {
50
+ lastError = error;
51
+ // Check if we should retry
52
+ const shouldRetry = attempt < config.maxAttempts && config.isRetryable(error);
53
+ if (!shouldRetry) {
54
+ throw error;
55
+ }
56
+ // Calculate delay with exponential backoff
57
+ const delay = Math.min(config.initialDelay * Math.pow(config.backoffMultiplier, attempt - 1), config.maxDelay);
58
+ // Notify about retry
59
+ config.onRetry(attempt, error);
60
+ // Wait before retrying
61
+ await sleep(delay);
62
+ }
63
+ }
64
+ throw lastError;
65
+ }
66
+ /**
67
+ * Executes an operation with a timeout
68
+ * @param promise Promise to execute
69
+ * @param timeoutMs Timeout in milliseconds
70
+ * @returns Result of the promise
71
+ */
72
+ async function withTimeout(promise, timeoutMs) {
73
+ let timeoutHandle = null;
74
+ const timeoutPromise = new Promise((_, reject) => {
75
+ timeoutHandle = setTimeout(() => {
76
+ reject(new errors_1.TimeoutError(`Operation timed out after ${timeoutMs}ms`));
77
+ }, timeoutMs);
78
+ // Use unref() to prevent this timer from keeping the process alive
79
+ if (timeoutHandle.unref) {
80
+ timeoutHandle.unref();
81
+ }
82
+ });
83
+ try {
84
+ const result = await Promise.race([promise, timeoutPromise]);
85
+ // Clear the timeout if the promise resolves first
86
+ if (timeoutHandle) {
87
+ clearTimeout(timeoutHandle);
88
+ }
89
+ return result;
90
+ }
91
+ catch (error) {
92
+ // Clear the timeout if the promise rejects
93
+ if (timeoutHandle) {
94
+ clearTimeout(timeoutHandle);
95
+ }
96
+ throw error;
97
+ }
98
+ }
99
+ /**
100
+ * Sleep for a specified duration
101
+ * @param ms Duration in milliseconds
102
+ */
103
+ function sleep(ms) {
104
+ return new Promise(resolve => setTimeout(resolve, ms));
105
+ }
106
+ /**
107
+ * Rate limiter to prevent exceeding API limits
108
+ */
109
+ class RateLimiter {
110
+ constructor(maxConcurrent = 5, minInterval = 100) {
111
+ this.maxConcurrent = maxConcurrent;
112
+ this.minInterval = minInterval;
113
+ this.queue = [];
114
+ this.activeRequests = 0;
115
+ }
116
+ /**
117
+ * Execute an operation with rate limiting
118
+ * @param operation Function to execute
119
+ * @returns Result of the operation
120
+ */
121
+ async execute(operation) {
122
+ // Wait for slot and reserve it
123
+ await this.reserveSlot();
124
+ try {
125
+ const result = await operation();
126
+ return result;
127
+ }
128
+ finally {
129
+ // Wait minimum interval before allowing next request
130
+ await sleep(this.minInterval);
131
+ // Release slot
132
+ this.activeRequests--;
133
+ const next = this.queue.shift();
134
+ if (next) {
135
+ next();
136
+ }
137
+ }
138
+ }
139
+ reserveSlot() {
140
+ if (this.activeRequests < this.maxConcurrent) {
141
+ this.activeRequests++;
142
+ return Promise.resolve();
143
+ }
144
+ return new Promise(resolve => {
145
+ this.queue.push(() => {
146
+ this.activeRequests++;
147
+ resolve();
148
+ });
149
+ });
150
+ }
151
+ }
152
+ exports.RateLimiter = RateLimiter;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Input validation utilities for Signal SDK
3
+ * Provides strict validation for all inputs
4
+ */
5
+ /**
6
+ * Validates a phone number format (E.164)
7
+ * @param phoneNumber Phone number to validate
8
+ * @throws ValidationError if invalid
9
+ */
10
+ export declare function validatePhoneNumber(phoneNumber: string): void;
11
+ /**
12
+ * Validates a group ID format
13
+ * @param groupId Group ID to validate
14
+ * @throws ValidationError if invalid
15
+ */
16
+ export declare function validateGroupId(groupId: string): void;
17
+ /**
18
+ * Validates a recipient (phone number, UUID, or username)
19
+ * @param recipient Recipient to validate
20
+ * @throws ValidationError if invalid
21
+ */
22
+ export declare function validateRecipient(recipient: string): void;
23
+ /**
24
+ * Validates a message text
25
+ * @param message Message to validate
26
+ * @param maxLength Maximum message length
27
+ * @throws ValidationError if invalid
28
+ */
29
+ export declare function validateMessage(message: string, maxLength?: number): void;
30
+ /**
31
+ * Validates file attachments
32
+ * @param attachments Array of attachment paths
33
+ * @throws ValidationError if invalid
34
+ */
35
+ export declare function validateAttachments(attachments: string[]): void;
36
+ /**
37
+ * Validates a timestamp
38
+ * @param timestamp Timestamp to validate
39
+ * @throws ValidationError if invalid
40
+ */
41
+ export declare function validateTimestamp(timestamp: number): void;
42
+ /**
43
+ * Validates an emoji string
44
+ * @param emoji Emoji to validate
45
+ * @throws ValidationError if invalid
46
+ */
47
+ export declare function validateEmoji(emoji: string): void;
48
+ /**
49
+ * Validates device ID
50
+ * @param deviceId Device ID to validate
51
+ * @throws ValidationError if invalid
52
+ */
53
+ export declare function validateDeviceId(deviceId: number): void;
54
+ /**
55
+ * Sanitizes user input to prevent injection attacks
56
+ * @param input Input string to sanitize
57
+ * @returns Sanitized string
58
+ */
59
+ export declare function sanitizeInput(input: string): string;