signal-sdk 0.0.8 → 0.1.0
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/README.md +175 -59
- package/dist/SignalBot.d.ts +108 -0
- package/dist/SignalBot.js +811 -0
- package/dist/SignalCli.d.ts +205 -0
- package/dist/SignalCli.js +967 -0
- package/dist/__tests__/SignalBot.additional.test.d.ts +5 -0
- package/dist/__tests__/SignalBot.additional.test.js +333 -0
- package/dist/__tests__/SignalBot.test.d.ts +1 -0
- package/dist/__tests__/SignalBot.test.js +102 -0
- package/dist/__tests__/SignalCli.integration.test.d.ts +5 -0
- package/dist/__tests__/SignalCli.integration.test.js +218 -0
- package/dist/__tests__/SignalCli.methods.test.d.ts +5 -0
- package/dist/__tests__/SignalCli.methods.test.js +470 -0
- package/dist/__tests__/SignalCli.test.d.ts +1 -0
- package/dist/__tests__/SignalCli.test.js +479 -0
- package/dist/__tests__/config.test.d.ts +5 -0
- package/dist/__tests__/config.test.js +252 -0
- package/dist/__tests__/errors.test.d.ts +5 -0
- package/dist/__tests__/errors.test.js +276 -0
- package/dist/__tests__/retry.test.d.ts +4 -0
- package/dist/__tests__/retry.test.js +123 -0
- package/dist/__tests__/validators.test.d.ts +4 -0
- package/dist/__tests__/validators.test.js +147 -0
- package/dist/config.d.ts +67 -0
- package/dist/config.js +111 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +75 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +26 -0
- package/dist/interfaces.d.ts +1073 -0
- package/dist/interfaces.js +11 -0
- package/dist/retry.d.ts +56 -0
- package/dist/retry.js +135 -0
- package/dist/validators.d.ts +59 -0
- package/dist/validators.js +170 -0
- package/package.json +5 -6
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Signal CLI SDK TypeScript Interfaces
|
|
4
|
+
*
|
|
5
|
+
* This file contains comprehensive type definitions for the Signal CLI SDK,
|
|
6
|
+
* which uses JSON-RPC communication with signal-cli for optimal performance.
|
|
7
|
+
*
|
|
8
|
+
* @author Signal SDK Team
|
|
9
|
+
* @version 0.1.0
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/retry.d.ts
ADDED
|
@@ -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,135 @@
|
|
|
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
|
+
return Promise.race([
|
|
74
|
+
promise,
|
|
75
|
+
new Promise((_, reject) => {
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
reject(new errors_1.TimeoutError(`Operation timed out after ${timeoutMs}ms`));
|
|
78
|
+
}, timeoutMs);
|
|
79
|
+
})
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Sleep for a specified duration
|
|
84
|
+
* @param ms Duration in milliseconds
|
|
85
|
+
*/
|
|
86
|
+
function sleep(ms) {
|
|
87
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Rate limiter to prevent exceeding API limits
|
|
91
|
+
*/
|
|
92
|
+
class RateLimiter {
|
|
93
|
+
constructor(maxConcurrent = 5, minInterval = 100) {
|
|
94
|
+
this.maxConcurrent = maxConcurrent;
|
|
95
|
+
this.minInterval = minInterval;
|
|
96
|
+
this.queue = [];
|
|
97
|
+
this.activeRequests = 0;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Execute an operation with rate limiting
|
|
101
|
+
* @param operation Function to execute
|
|
102
|
+
* @returns Result of the operation
|
|
103
|
+
*/
|
|
104
|
+
async execute(operation) {
|
|
105
|
+
// Wait for slot and reserve it
|
|
106
|
+
await this.reserveSlot();
|
|
107
|
+
try {
|
|
108
|
+
const result = await operation();
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
// Wait minimum interval before allowing next request
|
|
113
|
+
await sleep(this.minInterval);
|
|
114
|
+
// Release slot
|
|
115
|
+
this.activeRequests--;
|
|
116
|
+
const next = this.queue.shift();
|
|
117
|
+
if (next) {
|
|
118
|
+
next();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
reserveSlot() {
|
|
123
|
+
if (this.activeRequests < this.maxConcurrent) {
|
|
124
|
+
this.activeRequests++;
|
|
125
|
+
return Promise.resolve();
|
|
126
|
+
}
|
|
127
|
+
return new Promise(resolve => {
|
|
128
|
+
this.queue.push(() => {
|
|
129
|
+
this.activeRequests++;
|
|
130
|
+
resolve();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
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;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Input validation utilities for Signal SDK
|
|
4
|
+
* Provides strict validation for all inputs
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.validatePhoneNumber = validatePhoneNumber;
|
|
8
|
+
exports.validateGroupId = validateGroupId;
|
|
9
|
+
exports.validateRecipient = validateRecipient;
|
|
10
|
+
exports.validateMessage = validateMessage;
|
|
11
|
+
exports.validateAttachments = validateAttachments;
|
|
12
|
+
exports.validateTimestamp = validateTimestamp;
|
|
13
|
+
exports.validateEmoji = validateEmoji;
|
|
14
|
+
exports.validateDeviceId = validateDeviceId;
|
|
15
|
+
exports.sanitizeInput = sanitizeInput;
|
|
16
|
+
const errors_1 = require("./errors");
|
|
17
|
+
/**
|
|
18
|
+
* Validates a phone number format (E.164)
|
|
19
|
+
* @param phoneNumber Phone number to validate
|
|
20
|
+
* @throws ValidationError if invalid
|
|
21
|
+
*/
|
|
22
|
+
function validatePhoneNumber(phoneNumber) {
|
|
23
|
+
if (!phoneNumber) {
|
|
24
|
+
throw new errors_1.ValidationError('Phone number is required', 'phoneNumber');
|
|
25
|
+
}
|
|
26
|
+
if (typeof phoneNumber !== 'string') {
|
|
27
|
+
throw new errors_1.ValidationError('Phone number must be a string', 'phoneNumber');
|
|
28
|
+
}
|
|
29
|
+
// E.164 format: + followed by 1-15 digits
|
|
30
|
+
const e164Regex = /^\+[1-9]\d{1,14}$/;
|
|
31
|
+
if (!e164Regex.test(phoneNumber)) {
|
|
32
|
+
throw new errors_1.ValidationError('Phone number must be in E.164 format (e.g., +33123456789)', 'phoneNumber');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Validates a group ID format
|
|
37
|
+
* @param groupId Group ID to validate
|
|
38
|
+
* @throws ValidationError if invalid
|
|
39
|
+
*/
|
|
40
|
+
function validateGroupId(groupId) {
|
|
41
|
+
if (!groupId) {
|
|
42
|
+
throw new errors_1.ValidationError('Group ID is required', 'groupId');
|
|
43
|
+
}
|
|
44
|
+
if (typeof groupId !== 'string') {
|
|
45
|
+
throw new errors_1.ValidationError('Group ID must be a string', 'groupId');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validates a recipient (phone number, UUID, or username)
|
|
50
|
+
* @param recipient Recipient to validate
|
|
51
|
+
* @throws ValidationError if invalid
|
|
52
|
+
*/
|
|
53
|
+
function validateRecipient(recipient) {
|
|
54
|
+
if (!recipient) {
|
|
55
|
+
throw new errors_1.ValidationError('Recipient is required', 'recipient');
|
|
56
|
+
}
|
|
57
|
+
if (typeof recipient !== 'string') {
|
|
58
|
+
throw new errors_1.ValidationError('Recipient must be a string', 'recipient');
|
|
59
|
+
}
|
|
60
|
+
// Check if it's a username (starts with u:)
|
|
61
|
+
if (recipient.startsWith('u:')) {
|
|
62
|
+
if (recipient.length < 3) {
|
|
63
|
+
throw new errors_1.ValidationError('Username is too short', 'recipient');
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Check if it's a UUID (PNI: prefix or plain UUID)
|
|
68
|
+
const uuidRegex = /^(PNI:)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
69
|
+
if (uuidRegex.test(recipient)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Otherwise, validate as phone number
|
|
73
|
+
validatePhoneNumber(recipient);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Validates a message text
|
|
77
|
+
* @param message Message to validate
|
|
78
|
+
* @param maxLength Maximum message length
|
|
79
|
+
* @throws ValidationError if invalid
|
|
80
|
+
*/
|
|
81
|
+
function validateMessage(message, maxLength = 10000) {
|
|
82
|
+
if (message === undefined || message === null) {
|
|
83
|
+
throw new errors_1.ValidationError('Message is required', 'message');
|
|
84
|
+
}
|
|
85
|
+
if (typeof message !== 'string') {
|
|
86
|
+
throw new errors_1.ValidationError('Message must be a string', 'message');
|
|
87
|
+
}
|
|
88
|
+
if (message.length > maxLength) {
|
|
89
|
+
throw new errors_1.ValidationError(`Message exceeds maximum length of ${maxLength} characters`, 'message');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Validates file attachments
|
|
94
|
+
* @param attachments Array of attachment paths
|
|
95
|
+
* @throws ValidationError if invalid
|
|
96
|
+
*/
|
|
97
|
+
function validateAttachments(attachments) {
|
|
98
|
+
if (!Array.isArray(attachments)) {
|
|
99
|
+
throw new errors_1.ValidationError('Attachments must be an array', 'attachments');
|
|
100
|
+
}
|
|
101
|
+
for (const attachment of attachments) {
|
|
102
|
+
if (typeof attachment !== 'string') {
|
|
103
|
+
throw new errors_1.ValidationError('Each attachment must be a file path string', 'attachments');
|
|
104
|
+
}
|
|
105
|
+
if (attachment.length === 0) {
|
|
106
|
+
throw new errors_1.ValidationError('Attachment path cannot be empty', 'attachments');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validates a timestamp
|
|
112
|
+
* @param timestamp Timestamp to validate
|
|
113
|
+
* @throws ValidationError if invalid
|
|
114
|
+
*/
|
|
115
|
+
function validateTimestamp(timestamp) {
|
|
116
|
+
if (typeof timestamp !== 'number') {
|
|
117
|
+
throw new errors_1.ValidationError('Timestamp must be a number', 'timestamp');
|
|
118
|
+
}
|
|
119
|
+
if (timestamp <= 0) {
|
|
120
|
+
throw new errors_1.ValidationError('Timestamp must be positive', 'timestamp');
|
|
121
|
+
}
|
|
122
|
+
if (!Number.isFinite(timestamp)) {
|
|
123
|
+
throw new errors_1.ValidationError('Timestamp must be finite', 'timestamp');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Validates an emoji string
|
|
128
|
+
* @param emoji Emoji to validate
|
|
129
|
+
* @throws ValidationError if invalid
|
|
130
|
+
*/
|
|
131
|
+
function validateEmoji(emoji) {
|
|
132
|
+
if (!emoji) {
|
|
133
|
+
throw new errors_1.ValidationError('Emoji is required', 'emoji');
|
|
134
|
+
}
|
|
135
|
+
if (typeof emoji !== 'string') {
|
|
136
|
+
throw new errors_1.ValidationError('Emoji must be a string', 'emoji');
|
|
137
|
+
}
|
|
138
|
+
// Basic emoji validation - should be a single grapheme cluster
|
|
139
|
+
if (emoji.length === 0 || emoji.length > 10) {
|
|
140
|
+
throw new errors_1.ValidationError('Invalid emoji format', 'emoji');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Validates device ID
|
|
145
|
+
* @param deviceId Device ID to validate
|
|
146
|
+
* @throws ValidationError if invalid
|
|
147
|
+
*/
|
|
148
|
+
function validateDeviceId(deviceId) {
|
|
149
|
+
if (typeof deviceId !== 'number') {
|
|
150
|
+
throw new errors_1.ValidationError('Device ID must be a number', 'deviceId');
|
|
151
|
+
}
|
|
152
|
+
if (!Number.isInteger(deviceId)) {
|
|
153
|
+
throw new errors_1.ValidationError('Device ID must be an integer', 'deviceId');
|
|
154
|
+
}
|
|
155
|
+
if (deviceId <= 0) {
|
|
156
|
+
throw new errors_1.ValidationError('Device ID must be positive', 'deviceId');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Sanitizes user input to prevent injection attacks
|
|
161
|
+
* @param input Input string to sanitize
|
|
162
|
+
* @returns Sanitized string
|
|
163
|
+
*/
|
|
164
|
+
function sanitizeInput(input) {
|
|
165
|
+
if (typeof input !== 'string') {
|
|
166
|
+
return '';
|
|
167
|
+
}
|
|
168
|
+
// Remove null bytes
|
|
169
|
+
return input.replace(/\0/g, '');
|
|
170
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signal-sdk",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A comprehensive TypeScript SDK for Signal Messenger with native JSON-RPC support, providing high-performance messaging, bot framework, and full signal-cli integration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
18
19
|
"test": "jest",
|
|
19
20
|
"postinstall": "node scripts/install.js",
|
|
20
21
|
"connect": "node scripts/connect.js",
|
|
@@ -25,7 +26,8 @@
|
|
|
25
26
|
"example:contact-management": "node examples/sdk/04-contact-management.js",
|
|
26
27
|
"example:file-handling": "node examples/sdk/05-file-handling.js",
|
|
27
28
|
"example:minimal-bot": "node examples/bot/01-minimal-bot.js",
|
|
28
|
-
"example:advanced-bot": "node examples/bot/02-advanced-bot.js"
|
|
29
|
+
"example:advanced-bot": "node examples/bot/02-advanced-bot.js",
|
|
30
|
+
"example:advanced-bot-2": "node examples/bot/03-advanced-bot.js"
|
|
29
31
|
},
|
|
30
32
|
"keywords": [
|
|
31
33
|
"signal",
|
|
@@ -53,6 +55,7 @@
|
|
|
53
55
|
"devDependencies": {
|
|
54
56
|
"@types/jest": "^30.0.0",
|
|
55
57
|
"@types/node": "^24.0.10",
|
|
58
|
+
"dotenv": "^16.4.5",
|
|
56
59
|
"@types/qrcode-terminal": "^0.12.2",
|
|
57
60
|
"@types/uuid": "^9.0.8",
|
|
58
61
|
"jest": "^30.0.4",
|
|
@@ -61,10 +64,6 @@
|
|
|
61
64
|
},
|
|
62
65
|
"dependencies": {
|
|
63
66
|
"axios": "^1.10.0",
|
|
64
|
-
"dotenv": "^16.4.5",
|
|
65
|
-
"duckduckgo-chat-interface": "^1.1.5",
|
|
66
|
-
"events": "^3.3.0",
|
|
67
|
-
"qrcode": "^1.5.3",
|
|
68
67
|
"qrcode-terminal": "^0.12.0",
|
|
69
68
|
"tar": "^7.4.3",
|
|
70
69
|
"uuid": "^9.0.1"
|