@k-msg/messaging 0.1.1 → 0.1.2
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/dist/delivery/tracker.d.ts +144 -0
- package/dist/hooks.d.ts +11 -0
- package/dist/index.d.ts +10 -854
- package/dist/index.js +94 -2031
- package/dist/index.js.map +97 -1
- package/dist/index.mjs +102 -0
- package/dist/index.mjs.map +97 -0
- package/dist/k-msg.d.ts +8 -0
- package/dist/personalization/variable.replacer.d.ts +139 -0
- package/dist/queue/job-queue.interface.d.ts +39 -0
- package/dist/queue/job.processor.d.ts +133 -0
- package/dist/queue/retry.handler.d.ts +105 -0
- package/dist/queue/sqlite-job-queue.d.ts +28 -0
- package/dist/sender/bulk.sender.d.ts +18 -0
- package/dist/types/message.types.d.ts +280 -0
- package/package.json +20 -13
- package/dist/index.cjs +0 -2084
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -854
package/dist/k-msg.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { KMsgError, type Provider, type Result, type SendOptions, type SendResult } from "@k-msg/core";
|
|
2
|
+
import type { KMsgHooks } from "./hooks";
|
|
3
|
+
export declare class KMsg {
|
|
4
|
+
private readonly provider;
|
|
5
|
+
private readonly hooks;
|
|
6
|
+
constructor(provider: Provider, hooks?: KMsgHooks);
|
|
7
|
+
send(options: SendOptions): Promise<Result<SendResult, KMsgError>>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variable replacement and personalization system
|
|
3
|
+
*/
|
|
4
|
+
import type { VariableMap } from "../types/message.types";
|
|
5
|
+
export interface VariableReplacementOptions {
|
|
6
|
+
variablePattern: RegExp;
|
|
7
|
+
allowUndefined: boolean;
|
|
8
|
+
undefinedReplacement: string;
|
|
9
|
+
caseSensitive: boolean;
|
|
10
|
+
enableFormatting: boolean;
|
|
11
|
+
enableConditionals: boolean;
|
|
12
|
+
enableLoops: boolean;
|
|
13
|
+
maxRecursionDepth: number;
|
|
14
|
+
}
|
|
15
|
+
export interface VariableInfo {
|
|
16
|
+
name: string;
|
|
17
|
+
value: any;
|
|
18
|
+
formatted: string;
|
|
19
|
+
type: "string" | "number" | "date" | "boolean" | "array" | "object" | "undefined";
|
|
20
|
+
position: {
|
|
21
|
+
start: number;
|
|
22
|
+
end: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface ReplacementResult {
|
|
26
|
+
content: string;
|
|
27
|
+
variables: VariableInfo[];
|
|
28
|
+
missingVariables: string[];
|
|
29
|
+
errors: ReplacementError[];
|
|
30
|
+
metadata: {
|
|
31
|
+
originalLength: number;
|
|
32
|
+
finalLength: number;
|
|
33
|
+
variableCount: number;
|
|
34
|
+
replacementTime: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface ReplacementError {
|
|
38
|
+
type: "missing_variable" | "format_error" | "syntax_error" | "recursion_limit";
|
|
39
|
+
message: string;
|
|
40
|
+
variable?: string;
|
|
41
|
+
position?: {
|
|
42
|
+
start: number;
|
|
43
|
+
end: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export interface ConditionalBlock {
|
|
47
|
+
condition: string;
|
|
48
|
+
content: string;
|
|
49
|
+
elseContent?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface LoopBlock {
|
|
52
|
+
variable: string;
|
|
53
|
+
array: string;
|
|
54
|
+
content: string;
|
|
55
|
+
}
|
|
56
|
+
export declare class VariableReplacer {
|
|
57
|
+
private options;
|
|
58
|
+
private defaultOptions;
|
|
59
|
+
constructor(options?: Partial<VariableReplacementOptions>);
|
|
60
|
+
/**
|
|
61
|
+
* Replace variables in content
|
|
62
|
+
*/
|
|
63
|
+
replace(content: string, variables: VariableMap): ReplacementResult;
|
|
64
|
+
/**
|
|
65
|
+
* Extract variables from content without replacing
|
|
66
|
+
*/
|
|
67
|
+
extractVariables(content: string): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Validate that all required variables are provided
|
|
70
|
+
*/
|
|
71
|
+
validate(content: string, variables: VariableMap): {
|
|
72
|
+
isValid: boolean;
|
|
73
|
+
missingVariables: string[];
|
|
74
|
+
errors: ReplacementError[];
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Preview replacement result without actually replacing
|
|
78
|
+
*/
|
|
79
|
+
preview(content: string, variables: VariableMap): {
|
|
80
|
+
originalContent: string;
|
|
81
|
+
previewContent: string;
|
|
82
|
+
variableHighlights: Array<{
|
|
83
|
+
variable: string;
|
|
84
|
+
value: string;
|
|
85
|
+
positions: Array<{
|
|
86
|
+
start: number;
|
|
87
|
+
end: number;
|
|
88
|
+
}>;
|
|
89
|
+
}>;
|
|
90
|
+
};
|
|
91
|
+
private replaceSimpleVariables;
|
|
92
|
+
private replaceRecursive;
|
|
93
|
+
private processConditionals;
|
|
94
|
+
private processLoops;
|
|
95
|
+
private parseVariableName;
|
|
96
|
+
private getVariableValue;
|
|
97
|
+
private formatValue;
|
|
98
|
+
private formatDate;
|
|
99
|
+
private getValueType;
|
|
100
|
+
private hasVariables;
|
|
101
|
+
private extractConditionals;
|
|
102
|
+
private extractLoops;
|
|
103
|
+
private extractVariablesFromExpression;
|
|
104
|
+
private evaluateCondition;
|
|
105
|
+
private buildConditionalPattern;
|
|
106
|
+
private buildLoopPattern;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Default instance with Korean-optimized settings
|
|
110
|
+
*/
|
|
111
|
+
export declare const defaultVariableReplacer: VariableReplacer;
|
|
112
|
+
/**
|
|
113
|
+
* Utility functions
|
|
114
|
+
*/
|
|
115
|
+
export declare const VariableUtils: {
|
|
116
|
+
/**
|
|
117
|
+
* Extract all variables from content
|
|
118
|
+
*/
|
|
119
|
+
extractVariables: (content: string) => string[];
|
|
120
|
+
/**
|
|
121
|
+
* Replace variables in content
|
|
122
|
+
*/
|
|
123
|
+
replace: (content: string, variables: VariableMap) => string;
|
|
124
|
+
/**
|
|
125
|
+
* Validate content has all required variables
|
|
126
|
+
*/
|
|
127
|
+
validate: (content: string, variables: VariableMap) => boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Create personalized content for multiple recipients
|
|
130
|
+
*/
|
|
131
|
+
personalize: (content: string, recipients: Array<{
|
|
132
|
+
phoneNumber: string;
|
|
133
|
+
variables: VariableMap;
|
|
134
|
+
}>) => Array<{
|
|
135
|
+
phoneNumber: string;
|
|
136
|
+
content: string;
|
|
137
|
+
errors?: string[];
|
|
138
|
+
}>;
|
|
139
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare enum JobStatus {
|
|
2
|
+
PENDING = "pending",
|
|
3
|
+
PROCESSING = "processing",
|
|
4
|
+
COMPLETED = "completed",
|
|
5
|
+
FAILED = "failed",
|
|
6
|
+
DELAYED = "delayed"
|
|
7
|
+
}
|
|
8
|
+
export interface Job<T> {
|
|
9
|
+
id: string;
|
|
10
|
+
type: string;
|
|
11
|
+
data: T;
|
|
12
|
+
status: JobStatus;
|
|
13
|
+
priority: number;
|
|
14
|
+
attempts: number;
|
|
15
|
+
maxAttempts: number;
|
|
16
|
+
delay: number;
|
|
17
|
+
createdAt: Date;
|
|
18
|
+
processAt: Date;
|
|
19
|
+
completedAt?: Date;
|
|
20
|
+
failedAt?: Date;
|
|
21
|
+
error?: string;
|
|
22
|
+
metadata: Record<string, any>;
|
|
23
|
+
}
|
|
24
|
+
export interface JobQueue<T> {
|
|
25
|
+
enqueue(type: string, data: T, options?: {
|
|
26
|
+
priority?: number;
|
|
27
|
+
delay?: number;
|
|
28
|
+
maxAttempts?: number;
|
|
29
|
+
metadata?: Record<string, any>;
|
|
30
|
+
}): Promise<Job<T>>;
|
|
31
|
+
dequeue(): Promise<Job<T> | undefined>;
|
|
32
|
+
complete(jobId: string, result?: any): Promise<void>;
|
|
33
|
+
fail(jobId: string, error: string | Error, shouldRetry?: boolean): Promise<void>;
|
|
34
|
+
peek(): Promise<Job<T> | undefined>;
|
|
35
|
+
size(): Promise<number>;
|
|
36
|
+
getJob(jobId: string): Promise<Job<T> | undefined>;
|
|
37
|
+
remove(jobId: string): Promise<boolean>;
|
|
38
|
+
clear(): Promise<void>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job processor for message queue system
|
|
3
|
+
*/
|
|
4
|
+
import { type Provider } from "@k-msg/core";
|
|
5
|
+
import { EventEmitter } from "events";
|
|
6
|
+
import { type MessageRequest } from "../types/message.types";
|
|
7
|
+
import type { Job, JobQueue } from "./job-queue.interface";
|
|
8
|
+
export interface JobProcessorOptions {
|
|
9
|
+
concurrency: number;
|
|
10
|
+
retryDelays: number[];
|
|
11
|
+
maxRetries: number;
|
|
12
|
+
pollInterval: number;
|
|
13
|
+
enableMetrics: boolean;
|
|
14
|
+
rateLimiter?: {
|
|
15
|
+
maxRequests: number;
|
|
16
|
+
windowMs: number;
|
|
17
|
+
};
|
|
18
|
+
circuitBreaker?: {
|
|
19
|
+
failureThreshold: number;
|
|
20
|
+
timeout: number;
|
|
21
|
+
resetTimeout: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export type JobHandler<T = any> = (job: Job<T>) => Promise<any>;
|
|
25
|
+
export interface JobProcessorMetrics {
|
|
26
|
+
processed: number;
|
|
27
|
+
succeeded: number;
|
|
28
|
+
failed: number;
|
|
29
|
+
retried: number;
|
|
30
|
+
activeJobs: number;
|
|
31
|
+
queueSize: number;
|
|
32
|
+
averageProcessingTime: number;
|
|
33
|
+
lastProcessedAt?: Date;
|
|
34
|
+
}
|
|
35
|
+
export declare class JobProcessor extends EventEmitter {
|
|
36
|
+
private options;
|
|
37
|
+
private handlers;
|
|
38
|
+
private queue;
|
|
39
|
+
private processing;
|
|
40
|
+
private isRunning;
|
|
41
|
+
private pollTimer?;
|
|
42
|
+
private metrics;
|
|
43
|
+
private rateLimiter?;
|
|
44
|
+
private circuitBreaker?;
|
|
45
|
+
constructor(options: JobProcessorOptions, jobQueue?: JobQueue<any>);
|
|
46
|
+
/**
|
|
47
|
+
* Register a job handler
|
|
48
|
+
*/
|
|
49
|
+
handle<T>(jobType: string, handler: JobHandler<T>): void;
|
|
50
|
+
/**
|
|
51
|
+
* Add a job to the queue
|
|
52
|
+
*/
|
|
53
|
+
add<T>(jobType: string, data: T, options?: {
|
|
54
|
+
priority?: number;
|
|
55
|
+
delay?: number;
|
|
56
|
+
maxAttempts?: number;
|
|
57
|
+
metadata?: Record<string, any>;
|
|
58
|
+
}): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Start processing jobs
|
|
61
|
+
*/
|
|
62
|
+
start(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Stop processing jobs
|
|
65
|
+
*/
|
|
66
|
+
stop(): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Get current metrics
|
|
69
|
+
*/
|
|
70
|
+
getMetrics(): JobProcessorMetrics;
|
|
71
|
+
/**
|
|
72
|
+
* Get queue status
|
|
73
|
+
*/
|
|
74
|
+
getQueueStatus(): Promise<{
|
|
75
|
+
pending: number;
|
|
76
|
+
processing: number;
|
|
77
|
+
failed: number;
|
|
78
|
+
totalProcessed: number;
|
|
79
|
+
}>;
|
|
80
|
+
/**
|
|
81
|
+
* Remove completed jobs from queue
|
|
82
|
+
*/
|
|
83
|
+
cleanup(): Promise<number>;
|
|
84
|
+
/**
|
|
85
|
+
* Get specific job by ID
|
|
86
|
+
*/
|
|
87
|
+
getJob(jobId: string): Promise<Job<any> | undefined>;
|
|
88
|
+
/**
|
|
89
|
+
* Remove job from queue
|
|
90
|
+
*/
|
|
91
|
+
removeJob(jobId: string): Promise<boolean>;
|
|
92
|
+
private scheduleNextPoll;
|
|
93
|
+
private processJobs;
|
|
94
|
+
private processJob;
|
|
95
|
+
private failJob;
|
|
96
|
+
private getRetryDelay;
|
|
97
|
+
private updateMetrics;
|
|
98
|
+
private updateAverageProcessingTime;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Specific processor for message jobs
|
|
102
|
+
*/
|
|
103
|
+
export declare class MessageJobProcessor extends JobProcessor {
|
|
104
|
+
private provider;
|
|
105
|
+
constructor(provider: Provider, options?: Partial<JobProcessorOptions>, jobQueue?: JobQueue<any>);
|
|
106
|
+
private setupMessageHandlers;
|
|
107
|
+
private processSingleMessage;
|
|
108
|
+
private processBulkMessages;
|
|
109
|
+
private processDeliveryUpdate;
|
|
110
|
+
private processScheduledMessage;
|
|
111
|
+
/**
|
|
112
|
+
* Add a message to the processing queue
|
|
113
|
+
*/
|
|
114
|
+
queueMessage(messageRequest: MessageRequest, options?: {
|
|
115
|
+
priority?: number;
|
|
116
|
+
delay?: number;
|
|
117
|
+
metadata?: Record<string, any>;
|
|
118
|
+
}): Promise<string>;
|
|
119
|
+
/**
|
|
120
|
+
* Add bulk messages to the processing queue
|
|
121
|
+
*/
|
|
122
|
+
queueBulkMessages(messageRequests: MessageRequest[], options?: {
|
|
123
|
+
priority?: number;
|
|
124
|
+
delay?: number;
|
|
125
|
+
metadata?: Record<string, any>;
|
|
126
|
+
}): Promise<string>;
|
|
127
|
+
/**
|
|
128
|
+
* Schedule a message for future delivery
|
|
129
|
+
*/
|
|
130
|
+
scheduleMessage(messageRequest: MessageRequest, scheduledAt: Date, options?: {
|
|
131
|
+
metadata?: Record<string, any>;
|
|
132
|
+
}): Promise<string>;
|
|
133
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry handler for failed message deliveries
|
|
3
|
+
*/
|
|
4
|
+
import { EventEmitter } from "events";
|
|
5
|
+
import { type DeliveryReport, MessageStatus } from "../types/message.types";
|
|
6
|
+
export interface RetryPolicy {
|
|
7
|
+
maxAttempts: number;
|
|
8
|
+
backoffMultiplier: number;
|
|
9
|
+
initialDelay: number;
|
|
10
|
+
maxDelay: number;
|
|
11
|
+
jitter: boolean;
|
|
12
|
+
retryableStatuses: MessageStatus[];
|
|
13
|
+
retryableErrorCodes: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface RetryAttempt {
|
|
16
|
+
messageId: string;
|
|
17
|
+
phoneNumber: string;
|
|
18
|
+
attemptNumber: number;
|
|
19
|
+
scheduledAt: Date;
|
|
20
|
+
provider: string;
|
|
21
|
+
templateId: string;
|
|
22
|
+
variables: Record<string, any>;
|
|
23
|
+
metadata: Record<string, any>;
|
|
24
|
+
}
|
|
25
|
+
export interface RetryQueueItem {
|
|
26
|
+
id: string;
|
|
27
|
+
messageId: string;
|
|
28
|
+
phoneNumber: string;
|
|
29
|
+
originalDeliveryReport: DeliveryReport;
|
|
30
|
+
attempts: RetryAttempt[];
|
|
31
|
+
nextRetryAt: Date;
|
|
32
|
+
status: "pending" | "processing" | "exhausted" | "cancelled";
|
|
33
|
+
createdAt: Date;
|
|
34
|
+
updatedAt: Date;
|
|
35
|
+
}
|
|
36
|
+
export interface RetryHandlerOptions {
|
|
37
|
+
policy: RetryPolicy;
|
|
38
|
+
checkInterval: number;
|
|
39
|
+
maxQueueSize: number;
|
|
40
|
+
enablePersistence: boolean;
|
|
41
|
+
onRetryExhausted?: (item: RetryQueueItem) => Promise<void>;
|
|
42
|
+
onRetrySuccess?: (item: RetryQueueItem, result: any) => Promise<void>;
|
|
43
|
+
onRetryFailed?: (item: RetryQueueItem, error: Error) => Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
export interface RetryHandlerMetrics {
|
|
46
|
+
totalRetries: number;
|
|
47
|
+
successfulRetries: number;
|
|
48
|
+
failedRetries: number;
|
|
49
|
+
exhaustedRetries: number;
|
|
50
|
+
queueSize: number;
|
|
51
|
+
averageRetryDelay: number;
|
|
52
|
+
lastRetryAt?: Date;
|
|
53
|
+
}
|
|
54
|
+
export declare class MessageRetryHandler extends EventEmitter {
|
|
55
|
+
private options;
|
|
56
|
+
private retryQueue;
|
|
57
|
+
private processing;
|
|
58
|
+
private checkTimer?;
|
|
59
|
+
private isRunning;
|
|
60
|
+
private metrics;
|
|
61
|
+
private defaultPolicy;
|
|
62
|
+
constructor(options: RetryHandlerOptions);
|
|
63
|
+
/**
|
|
64
|
+
* Start the retry handler
|
|
65
|
+
*/
|
|
66
|
+
start(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Stop the retry handler
|
|
69
|
+
*/
|
|
70
|
+
stop(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Add a failed delivery for retry
|
|
73
|
+
*/
|
|
74
|
+
addForRetry(deliveryReport: DeliveryReport): Promise<boolean>;
|
|
75
|
+
/**
|
|
76
|
+
* Cancel retry for a specific message
|
|
77
|
+
*/
|
|
78
|
+
cancelRetry(messageId: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Get retry status for a message
|
|
81
|
+
*/
|
|
82
|
+
getRetryStatus(messageId: string): RetryQueueItem | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Get all retry queue items
|
|
85
|
+
*/
|
|
86
|
+
getRetryQueue(): RetryQueueItem[];
|
|
87
|
+
/**
|
|
88
|
+
* Get metrics
|
|
89
|
+
*/
|
|
90
|
+
getMetrics(): RetryHandlerMetrics;
|
|
91
|
+
/**
|
|
92
|
+
* Clean up completed/exhausted retry items
|
|
93
|
+
*/
|
|
94
|
+
cleanup(): number;
|
|
95
|
+
private scheduleNextCheck;
|
|
96
|
+
private processRetryQueue;
|
|
97
|
+
private processRetryItem;
|
|
98
|
+
private executeRetry;
|
|
99
|
+
private shouldRetry;
|
|
100
|
+
private createRetryItem;
|
|
101
|
+
private updateRetryItem;
|
|
102
|
+
private calculateRetryDelay;
|
|
103
|
+
private cleanupQueue;
|
|
104
|
+
private updateMetrics;
|
|
105
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Job, type JobQueue } from "./job-queue.interface";
|
|
2
|
+
interface SQLiteJobQueueOptions {
|
|
3
|
+
dbPath?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare class SQLiteJobQueue<T> implements JobQueue<T> {
|
|
6
|
+
private db;
|
|
7
|
+
constructor(options?: SQLiteJobQueueOptions);
|
|
8
|
+
private initializeSchema;
|
|
9
|
+
private jobToRow;
|
|
10
|
+
private rowToJob;
|
|
11
|
+
private generateId;
|
|
12
|
+
enqueue(type: string, data: T, options?: {
|
|
13
|
+
priority?: number;
|
|
14
|
+
delay?: number;
|
|
15
|
+
maxAttempts?: number;
|
|
16
|
+
metadata?: Record<string, any>;
|
|
17
|
+
}): Promise<Job<T>>;
|
|
18
|
+
dequeue(): Promise<Job<T> | undefined>;
|
|
19
|
+
complete(jobId: string, _result?: any): Promise<void>;
|
|
20
|
+
fail(jobId: string, error: string | Error, shouldRetry?: boolean): Promise<void>;
|
|
21
|
+
peek(): Promise<Job<T> | undefined>;
|
|
22
|
+
size(): Promise<number>;
|
|
23
|
+
getJob(jobId: string): Promise<Job<T> | undefined>;
|
|
24
|
+
remove(jobId: string): Promise<boolean>;
|
|
25
|
+
clear(): Promise<void>;
|
|
26
|
+
close(): void;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { KMsg } from "../k-msg";
|
|
2
|
+
import { type BulkBatchResult, type BulkMessageRequest, type BulkMessageResult } from "../types/message.types";
|
|
3
|
+
export declare class BulkMessageSender {
|
|
4
|
+
private kmsg;
|
|
5
|
+
private activeBulkJobs;
|
|
6
|
+
constructor(kmsg: KMsg);
|
|
7
|
+
sendBulk(request: BulkMessageRequest): Promise<BulkMessageResult>;
|
|
8
|
+
private processBatchesAsync;
|
|
9
|
+
private processBatch;
|
|
10
|
+
private processRecipient;
|
|
11
|
+
private createBatches;
|
|
12
|
+
private delay;
|
|
13
|
+
private generateRequestId;
|
|
14
|
+
getBulkStatus(requestId: string): Promise<BulkMessageResult | null>;
|
|
15
|
+
cancelBulkJob(requestId: string): Promise<boolean>;
|
|
16
|
+
retryFailedBatch(requestId: string, batchId: string): Promise<BulkBatchResult | null>;
|
|
17
|
+
cleanup(): void;
|
|
18
|
+
}
|