vocal-stack 1.0.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/LICENSE +21 -0
- package/README.md +269 -0
- package/dist/flow/index.cjs +571 -0
- package/dist/flow/index.cjs.map +1 -0
- package/dist/flow/index.d.cts +337 -0
- package/dist/flow/index.d.ts +337 -0
- package/dist/flow/index.js +559 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/index.cjs +1026 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +1003 -0
- package/dist/index.js.map +1 -0
- package/dist/monitor/index.cjs +291 -0
- package/dist/monitor/index.cjs.map +1 -0
- package/dist/monitor/index.d.cts +122 -0
- package/dist/monitor/index.d.ts +122 -0
- package/dist/monitor/index.js +286 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/sanitizer/index.cjs +190 -0
- package/dist/sanitizer/index.cjs.map +1 -0
- package/dist/sanitizer/index.d.cts +83 -0
- package/dist/sanitizer/index.d.ts +83 -0
- package/dist/sanitizer/index.js +186 -0
- package/dist/sanitizer/index.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for text sanitization
|
|
3
|
+
*/
|
|
4
|
+
interface SanitizerConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Rules to apply during sanitization
|
|
7
|
+
* @default ['markdown', 'urls', 'code-blocks', 'punctuation']
|
|
8
|
+
*/
|
|
9
|
+
readonly rules?: readonly SanitizerRule[];
|
|
10
|
+
/**
|
|
11
|
+
* Custom plugins for platform-specific transformations
|
|
12
|
+
*/
|
|
13
|
+
readonly plugins?: readonly SanitizerPlugin[];
|
|
14
|
+
/**
|
|
15
|
+
* Whether to preserve line breaks
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
readonly preserveLineBreaks?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Custom replacements for specific patterns
|
|
21
|
+
*/
|
|
22
|
+
readonly customReplacements?: ReadonlyMap<string | RegExp, string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Built-in rule identifiers
|
|
26
|
+
*/
|
|
27
|
+
type SanitizerRule = 'markdown' | 'urls' | 'code-blocks' | 'punctuation';
|
|
28
|
+
/**
|
|
29
|
+
* Plugin interface for custom sanitization logic
|
|
30
|
+
*/
|
|
31
|
+
interface SanitizerPlugin {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly priority: number;
|
|
34
|
+
transform(text: string): string | Promise<string>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result of sanitization operation
|
|
38
|
+
*/
|
|
39
|
+
interface SanitizationResult {
|
|
40
|
+
readonly original: string;
|
|
41
|
+
readonly sanitized: string;
|
|
42
|
+
readonly appliedRules: readonly string[];
|
|
43
|
+
readonly metadata: {
|
|
44
|
+
readonly removedCount: number;
|
|
45
|
+
readonly transformedCount: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Rule function type
|
|
50
|
+
*/
|
|
51
|
+
type RuleFunction = (text: string, config: Required<SanitizerConfig>) => string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Speech sanitizer that transforms text for TTS optimization
|
|
55
|
+
*/
|
|
56
|
+
declare class SpeechSanitizer {
|
|
57
|
+
private readonly config;
|
|
58
|
+
private readonly plugins;
|
|
59
|
+
constructor(config?: SanitizerConfig);
|
|
60
|
+
/**
|
|
61
|
+
* Sanitize a string synchronously
|
|
62
|
+
*/
|
|
63
|
+
sanitize(text: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Sanitize with detailed result metadata
|
|
66
|
+
*/
|
|
67
|
+
sanitizeWithMetadata(text: string): SanitizationResult;
|
|
68
|
+
/**
|
|
69
|
+
* Sanitize a stream of text chunks (AsyncIterable)
|
|
70
|
+
*/
|
|
71
|
+
sanitizeStream(input: AsyncIterable<string>): AsyncIterable<string>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Convenience function for one-off sanitization
|
|
75
|
+
*/
|
|
76
|
+
declare function sanitizeForSpeech(text: string, config?: SanitizerConfig): string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Registry of built-in sanitization rules
|
|
80
|
+
*/
|
|
81
|
+
declare const ruleRegistry: Map<string, RuleFunction>;
|
|
82
|
+
|
|
83
|
+
export { type RuleFunction, type SanitizationResult, type SanitizerConfig, type SanitizerPlugin, type SanitizerRule, SpeechSanitizer, ruleRegistry, sanitizeForSpeech };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for text sanitization
|
|
3
|
+
*/
|
|
4
|
+
interface SanitizerConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Rules to apply during sanitization
|
|
7
|
+
* @default ['markdown', 'urls', 'code-blocks', 'punctuation']
|
|
8
|
+
*/
|
|
9
|
+
readonly rules?: readonly SanitizerRule[];
|
|
10
|
+
/**
|
|
11
|
+
* Custom plugins for platform-specific transformations
|
|
12
|
+
*/
|
|
13
|
+
readonly plugins?: readonly SanitizerPlugin[];
|
|
14
|
+
/**
|
|
15
|
+
* Whether to preserve line breaks
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
readonly preserveLineBreaks?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Custom replacements for specific patterns
|
|
21
|
+
*/
|
|
22
|
+
readonly customReplacements?: ReadonlyMap<string | RegExp, string>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Built-in rule identifiers
|
|
26
|
+
*/
|
|
27
|
+
type SanitizerRule = 'markdown' | 'urls' | 'code-blocks' | 'punctuation';
|
|
28
|
+
/**
|
|
29
|
+
* Plugin interface for custom sanitization logic
|
|
30
|
+
*/
|
|
31
|
+
interface SanitizerPlugin {
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly priority: number;
|
|
34
|
+
transform(text: string): string | Promise<string>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result of sanitization operation
|
|
38
|
+
*/
|
|
39
|
+
interface SanitizationResult {
|
|
40
|
+
readonly original: string;
|
|
41
|
+
readonly sanitized: string;
|
|
42
|
+
readonly appliedRules: readonly string[];
|
|
43
|
+
readonly metadata: {
|
|
44
|
+
readonly removedCount: number;
|
|
45
|
+
readonly transformedCount: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Rule function type
|
|
50
|
+
*/
|
|
51
|
+
type RuleFunction = (text: string, config: Required<SanitizerConfig>) => string;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Speech sanitizer that transforms text for TTS optimization
|
|
55
|
+
*/
|
|
56
|
+
declare class SpeechSanitizer {
|
|
57
|
+
private readonly config;
|
|
58
|
+
private readonly plugins;
|
|
59
|
+
constructor(config?: SanitizerConfig);
|
|
60
|
+
/**
|
|
61
|
+
* Sanitize a string synchronously
|
|
62
|
+
*/
|
|
63
|
+
sanitize(text: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Sanitize with detailed result metadata
|
|
66
|
+
*/
|
|
67
|
+
sanitizeWithMetadata(text: string): SanitizationResult;
|
|
68
|
+
/**
|
|
69
|
+
* Sanitize a stream of text chunks (AsyncIterable)
|
|
70
|
+
*/
|
|
71
|
+
sanitizeStream(input: AsyncIterable<string>): AsyncIterable<string>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Convenience function for one-off sanitization
|
|
75
|
+
*/
|
|
76
|
+
declare function sanitizeForSpeech(text: string, config?: SanitizerConfig): string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Registry of built-in sanitization rules
|
|
80
|
+
*/
|
|
81
|
+
declare const ruleRegistry: Map<string, RuleFunction>;
|
|
82
|
+
|
|
83
|
+
export { type RuleFunction, type SanitizationResult, type SanitizerConfig, type SanitizerPlugin, type SanitizerRule, SpeechSanitizer, ruleRegistry, sanitizeForSpeech };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var VocalStackError = class extends Error {
|
|
3
|
+
constructor(message, code, context) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.context = context;
|
|
7
|
+
this.name = "VocalStackError";
|
|
8
|
+
Error.captureStackTrace(this, this.constructor);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var SanitizerError = class extends VocalStackError {
|
|
12
|
+
constructor(message, context) {
|
|
13
|
+
super(message, "SANITIZER_ERROR", context);
|
|
14
|
+
this.name = "SanitizerError";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/sanitizer/rules/code-blocks.ts
|
|
19
|
+
function codeBlocksRule(text, _config) {
|
|
20
|
+
let result = text;
|
|
21
|
+
result = result.replace(/```[\s\S]*?```/g, "");
|
|
22
|
+
result = result.replace(/^(?: {4}|\t).+$/gm, "");
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/sanitizer/rules/markdown.ts
|
|
27
|
+
function markdownRule(text, _config) {
|
|
28
|
+
let result = text;
|
|
29
|
+
result = result.replace(/^#{1,6}\s+/gm, "");
|
|
30
|
+
result = result.replace(/(\*\*|__)(.*?)\1/g, "$2");
|
|
31
|
+
result = result.replace(/(\*|_)(.*?)\1/g, "$2");
|
|
32
|
+
result = result.replace(/`([^`]+)`/g, "$1");
|
|
33
|
+
result = result.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
|
|
34
|
+
result = result.replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1");
|
|
35
|
+
result = result.replace(/^>\s+/gm, "");
|
|
36
|
+
result = result.replace(/^[\-*_]{3,}$/gm, "");
|
|
37
|
+
result = result.replace(/^[\s]*[-*+]\s+/gm, "");
|
|
38
|
+
result = result.replace(/^[\s]*\d+\.\s+/gm, "");
|
|
39
|
+
result = result.replace(/~~(.*?)~~/g, "$1");
|
|
40
|
+
result = result.replace(/^[\s]*-\s+\[[ xX]\]\s+/gm, "");
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/sanitizer/rules/punctuation.ts
|
|
45
|
+
function punctuationRule(text, _config) {
|
|
46
|
+
let result = text;
|
|
47
|
+
result = result.replace(/!{2,}/g, "!");
|
|
48
|
+
result = result.replace(/\?{2,}/g, "?");
|
|
49
|
+
result = result.replace(/\.{3,}/g, ".");
|
|
50
|
+
result = result.replace(/-{2,}/g, " ");
|
|
51
|
+
result = result.replace(/[—–]/g, " ");
|
|
52
|
+
result = result.replace(/[()[\]{}]/g, "");
|
|
53
|
+
result = result.replace(/,{2,}/g, ",");
|
|
54
|
+
result = result.replace(/[;:]/g, ",");
|
|
55
|
+
result = result.replace(/["'"'`]/g, "");
|
|
56
|
+
result = result.replace(/[*_]/g, "");
|
|
57
|
+
result = result.replace(/[/\\]/g, " ");
|
|
58
|
+
result = result.replace(/[|&]/g, " ");
|
|
59
|
+
result = result.replace(/[@#$%]/g, "");
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/sanitizer/rules/urls.ts
|
|
64
|
+
function urlsRule(text, _config) {
|
|
65
|
+
let result = text;
|
|
66
|
+
const urlWithProtocol = /\b(https?:\/\/|ftp:\/\/|www\.)[^\s<>"{}|\\^`[\]]+/gi;
|
|
67
|
+
const emailPattern = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g;
|
|
68
|
+
result = result.replace(urlWithProtocol, "");
|
|
69
|
+
result = result.replace(emailPattern, "");
|
|
70
|
+
result = result.replace(/\b[a-z0-9-]+\.[a-z]{2,}\b/gi, "");
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/sanitizer/rules/index.ts
|
|
75
|
+
var ruleRegistry = /* @__PURE__ */ new Map([
|
|
76
|
+
["markdown", markdownRule],
|
|
77
|
+
["urls", urlsRule],
|
|
78
|
+
["code-blocks", codeBlocksRule],
|
|
79
|
+
["punctuation", punctuationRule]
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
// src/sanitizer/sanitizer.ts
|
|
83
|
+
var SpeechSanitizer = class {
|
|
84
|
+
config;
|
|
85
|
+
plugins;
|
|
86
|
+
constructor(config = {}) {
|
|
87
|
+
this.config = {
|
|
88
|
+
rules: config.rules ?? ["markdown", "urls", "code-blocks", "punctuation"],
|
|
89
|
+
plugins: config.plugins ?? [],
|
|
90
|
+
preserveLineBreaks: config.preserveLineBreaks ?? false,
|
|
91
|
+
customReplacements: config.customReplacements ?? /* @__PURE__ */ new Map()
|
|
92
|
+
};
|
|
93
|
+
this.plugins = [...this.config.plugins].sort((a, b) => a.priority - b.priority);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Sanitize a string synchronously
|
|
97
|
+
*/
|
|
98
|
+
sanitize(text) {
|
|
99
|
+
if (!text || text.trim().length === 0) {
|
|
100
|
+
return "";
|
|
101
|
+
}
|
|
102
|
+
let result = text;
|
|
103
|
+
try {
|
|
104
|
+
for (const rule of this.config.rules) {
|
|
105
|
+
const ruleFunction = ruleRegistry.get(rule);
|
|
106
|
+
if (ruleFunction) {
|
|
107
|
+
result = ruleFunction(result, this.config);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const plugin of this.plugins) {
|
|
111
|
+
const transformed = plugin.transform(result);
|
|
112
|
+
if (transformed instanceof Promise) {
|
|
113
|
+
throw new SanitizerError(
|
|
114
|
+
`Plugin ${plugin.name} returned a Promise in sync sanitize(). Use sanitizeAsync() instead.`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
result = transformed;
|
|
118
|
+
}
|
|
119
|
+
for (const [pattern, replacement] of this.config.customReplacements) {
|
|
120
|
+
if (typeof pattern === "string") {
|
|
121
|
+
result = result.replaceAll(pattern, replacement);
|
|
122
|
+
} else {
|
|
123
|
+
result = result.replace(pattern, replacement);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (this.config.preserveLineBreaks) {
|
|
127
|
+
result = result.replace(/ +/g, " ").replace(/^\s+|\s+$/gm, "");
|
|
128
|
+
} else {
|
|
129
|
+
result = result.replace(/\s+/g, " ").trim();
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (error instanceof SanitizerError) {
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
throw new SanitizerError("Failed to sanitize text", {
|
|
137
|
+
originalText: text.substring(0, 100),
|
|
138
|
+
error
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Sanitize with detailed result metadata
|
|
144
|
+
*/
|
|
145
|
+
sanitizeWithMetadata(text) {
|
|
146
|
+
const original = text;
|
|
147
|
+
const sanitized = this.sanitize(text);
|
|
148
|
+
return {
|
|
149
|
+
original,
|
|
150
|
+
sanitized,
|
|
151
|
+
appliedRules: this.config.rules,
|
|
152
|
+
metadata: {
|
|
153
|
+
removedCount: original.length - sanitized.length,
|
|
154
|
+
transformedCount: this.config.rules.length + this.plugins.length
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Sanitize a stream of text chunks (AsyncIterable)
|
|
160
|
+
*/
|
|
161
|
+
async *sanitizeStream(input) {
|
|
162
|
+
let buffer = "";
|
|
163
|
+
const sentenceBoundary = /[.!?]\s+/;
|
|
164
|
+
for await (const chunk of input) {
|
|
165
|
+
buffer += chunk;
|
|
166
|
+
const sentences = buffer.split(sentenceBoundary);
|
|
167
|
+
buffer = sentences.pop() ?? "";
|
|
168
|
+
for (const sentence of sentences) {
|
|
169
|
+
if (sentence.trim()) {
|
|
170
|
+
yield `${this.sanitize(sentence)} `;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (buffer.trim()) {
|
|
175
|
+
yield this.sanitize(buffer);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
function sanitizeForSpeech(text, config) {
|
|
180
|
+
const sanitizer = new SpeechSanitizer(config);
|
|
181
|
+
return sanitizer.sanitize(text);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export { SpeechSanitizer, ruleRegistry, sanitizeForSpeech };
|
|
185
|
+
//# sourceMappingURL=index.js.map
|
|
186
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/sanitizer/rules/code-blocks.ts","../../src/sanitizer/rules/markdown.ts","../../src/sanitizer/rules/punctuation.ts","../../src/sanitizer/rules/urls.ts","../../src/sanitizer/rules/index.ts","../../src/sanitizer/sanitizer.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base error class for all vocal-stack errors\n */\nexport class VocalStackError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly context?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'VocalStackError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown during text sanitization\n */\nexport class SanitizerError extends VocalStackError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'SANITIZER_ERROR', context);\n this.name = 'SanitizerError';\n }\n}\n\n/**\n * Error thrown during flow control operations\n */\nexport class FlowControlError extends VocalStackError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'FLOW_CONTROL_ERROR', context);\n this.name = 'FlowControlError';\n }\n}\n\n/**\n * Error thrown during monitoring operations\n */\nexport class MonitorError extends VocalStackError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'MONITOR_ERROR', context);\n this.name = 'MonitorError';\n }\n}\n","import type { SanitizerConfig } from '../types';\n\n/**\n * Remove code blocks and inline code to make text speakable\n */\nexport function codeBlocksRule(text: string, _config: Required<SanitizerConfig>): string {\n let result = text;\n\n // Remove fenced code blocks (```code```)\n // Match both with and without language specifier\n result = result.replace(/```[\\s\\S]*?```/g, '');\n\n // Remove indented code blocks (4 spaces or 1 tab at line start)\n result = result.replace(/^(?: {4}|\\t).+$/gm, '');\n\n // Note: Inline code (`code`) is handled by markdown rule\n\n return result;\n}\n","import type { SanitizerConfig } from '../types';\n\n/**\n * Strip markdown syntax to make text speakable\n */\nexport function markdownRule(text: string, _config: Required<SanitizerConfig>): string {\n let result = text;\n\n // Remove headers (##, ###, etc.)\n result = result.replace(/^#{1,6}\\s+/gm, '');\n\n // Remove bold/italic (**text**, *text*, __text__, _text_)\n result = result.replace(/(\\*\\*|__)(.*?)\\1/g, '$2');\n result = result.replace(/(\\*|_)(.*?)\\1/g, '$2');\n\n // Remove inline code (`code`)\n result = result.replace(/`([^`]+)`/g, '$1');\n\n // Remove links but keep text [text](url) -> text\n result = result.replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1');\n\n // Remove images  -> alt or empty\n result = result.replace(/!\\[([^\\]]*)\\]\\([^)]+\\)/g, '$1');\n\n // Remove blockquotes (>)\n result = result.replace(/^>\\s+/gm, '');\n\n // Remove horizontal rules (---, ***, ___)\n result = result.replace(/^[\\-*_]{3,}$/gm, '');\n\n // Remove list markers (-, *, 1., etc.)\n result = result.replace(/^[\\s]*[-*+]\\s+/gm, '');\n result = result.replace(/^[\\s]*\\d+\\.\\s+/gm, '');\n\n // Remove strikethrough (~~text~~)\n result = result.replace(/~~(.*?)~~/g, '$1');\n\n // Remove task list markers (- [ ], - [x])\n result = result.replace(/^[\\s]*-\\s+\\[[ xX]\\]\\s+/gm, '');\n\n return result;\n}\n","import type { SanitizerConfig } from '../types';\n\n/**\n * Normalize punctuation for better TTS handling\n */\nexport function punctuationRule(text: string, _config: Required<SanitizerConfig>): string {\n let result = text;\n\n // Replace multiple exclamation marks with single\n result = result.replace(/!{2,}/g, '!');\n\n // Replace multiple question marks with single\n result = result.replace(/\\?{2,}/g, '?');\n\n // Replace ellipsis variations with single space or period\n result = result.replace(/\\.{3,}/g, '.');\n\n // Remove multiple dashes/hyphens\n result = result.replace(/-{2,}/g, ' ');\n\n // Replace em dash and en dash with space\n result = result.replace(/[—–]/g, ' ');\n\n // Remove parentheses and brackets but keep content\n result = result.replace(/[()[\\]{}]/g, '');\n\n // Replace multiple commas with single\n result = result.replace(/,{2,}/g, ',');\n\n // Remove semicolons and colons (can be disruptive in speech)\n result = result.replace(/[;:]/g, ',');\n\n // Remove quotation marks\n result = result.replace(/[\"'\"'`]/g, '');\n\n // Remove asterisks and underscores (from markdown remnants)\n result = result.replace(/[*_]/g, '');\n\n // Remove forward slashes and backslashes\n result = result.replace(/[/\\\\]/g, ' ');\n\n // Remove pipes and ampersands\n result = result.replace(/[|&]/g, ' ');\n\n // Remove @ # $ % symbols\n result = result.replace(/[@#$%]/g, '');\n\n return result;\n}\n","import type { SanitizerConfig } from '../types';\n\n/**\n * Remove or replace URLs to make text speakable\n */\nexport function urlsRule(text: string, _config: Required<SanitizerConfig>): string {\n let result = text;\n\n // Match URLs with protocol (http://, https://, ftp://, etc.)\n const urlWithProtocol = /\\b(https?:\\/\\/|ftp:\\/\\/|www\\.)[^\\s<>\"{}|\\\\^`[\\]]+/gi;\n\n // Match email addresses\n const emailPattern = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g;\n\n // Remove URLs with protocol\n result = result.replace(urlWithProtocol, '');\n\n // Remove email addresses\n result = result.replace(emailPattern, '');\n\n // Remove standalone domain-like patterns (example.com)\n result = result.replace(/\\b[a-z0-9-]+\\.[a-z]{2,}\\b/gi, '');\n\n return result;\n}\n","import type { RuleFunction } from '../types';\nimport { codeBlocksRule } from './code-blocks';\nimport { markdownRule } from './markdown';\nimport { punctuationRule } from './punctuation';\nimport { urlsRule } from './urls';\n\n/**\n * Registry of built-in sanitization rules\n */\nexport const ruleRegistry = new Map<string, RuleFunction>([\n ['markdown', markdownRule],\n ['urls', urlsRule],\n ['code-blocks', codeBlocksRule],\n ['punctuation', punctuationRule],\n]);\n","import { SanitizerError } from '../errors';\nimport { ruleRegistry } from './rules';\nimport type { SanitizationResult, SanitizerConfig, SanitizerPlugin } from './types';\n\n/**\n * Speech sanitizer that transforms text for TTS optimization\n */\nexport class SpeechSanitizer {\n private readonly config: Required<SanitizerConfig>;\n private readonly plugins: readonly SanitizerPlugin[];\n\n constructor(config: SanitizerConfig = {}) {\n this.config = {\n rules: config.rules ?? ['markdown', 'urls', 'code-blocks', 'punctuation'],\n plugins: config.plugins ?? [],\n preserveLineBreaks: config.preserveLineBreaks ?? false,\n customReplacements: config.customReplacements ?? new Map(),\n };\n this.plugins = [...this.config.plugins].sort((a, b) => a.priority - b.priority);\n }\n\n /**\n * Sanitize a string synchronously\n */\n sanitize(text: string): string {\n if (!text || text.trim().length === 0) {\n return '';\n }\n\n let result = text;\n\n try {\n // Apply built-in rules\n for (const rule of this.config.rules) {\n const ruleFunction = ruleRegistry.get(rule);\n if (ruleFunction) {\n result = ruleFunction(result, this.config);\n }\n }\n\n // Apply plugins (sync only in this version)\n for (const plugin of this.plugins) {\n const transformed = plugin.transform(result);\n if (transformed instanceof Promise) {\n throw new SanitizerError(\n `Plugin ${plugin.name} returned a Promise in sync sanitize(). Use sanitizeAsync() instead.`\n );\n }\n result = transformed;\n }\n\n // Apply custom replacements\n for (const [pattern, replacement] of this.config.customReplacements) {\n if (typeof pattern === 'string') {\n result = result.replaceAll(pattern, replacement);\n } else {\n result = result.replace(pattern, replacement);\n }\n }\n\n // Clean up whitespace\n if (this.config.preserveLineBreaks) {\n // Collapse multiple spaces on same line but keep line breaks\n result = result.replace(/ +/g, ' ').replace(/^\\s+|\\s+$/gm, '');\n } else {\n // Collapse all whitespace including line breaks\n result = result.replace(/\\s+/g, ' ').trim();\n }\n\n return result;\n } catch (error) {\n if (error instanceof SanitizerError) {\n throw error;\n }\n throw new SanitizerError('Failed to sanitize text', {\n originalText: text.substring(0, 100),\n error,\n });\n }\n }\n\n /**\n * Sanitize with detailed result metadata\n */\n sanitizeWithMetadata(text: string): SanitizationResult {\n const original = text;\n const sanitized = this.sanitize(text);\n\n return {\n original,\n sanitized,\n appliedRules: this.config.rules as string[],\n metadata: {\n removedCount: original.length - sanitized.length,\n transformedCount: this.config.rules.length + this.plugins.length,\n },\n };\n }\n\n /**\n * Sanitize a stream of text chunks (AsyncIterable)\n */\n async *sanitizeStream(input: AsyncIterable<string>): AsyncIterable<string> {\n let buffer = '';\n const sentenceBoundary = /[.!?]\\s+/;\n\n for await (const chunk of input) {\n buffer += chunk;\n\n // Process complete sentences\n const sentences = buffer.split(sentenceBoundary);\n buffer = sentences.pop() ?? ''; // Keep incomplete sentence\n\n for (const sentence of sentences) {\n if (sentence.trim()) {\n yield `${this.sanitize(sentence)} `;\n }\n }\n }\n\n // Process remaining buffer\n if (buffer.trim()) {\n yield this.sanitize(buffer);\n }\n }\n}\n\n/**\n * Convenience function for one-off sanitization\n */\nexport function sanitizeForSpeech(text: string, config?: SanitizerConfig): string {\n const sanitizer = new SpeechSanitizer(config);\n return sanitizer.sanitize(text);\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vocal-stack",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "High-performance utility library for Voice AI agents - text sanitization, flow control, and latency monitoring",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.mjs",
|
|
10
|
+
"require": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./sanitizer": {
|
|
13
|
+
"types": "./dist/sanitizer/index.d.ts",
|
|
14
|
+
"import": "./dist/sanitizer/index.mjs",
|
|
15
|
+
"require": "./dist/sanitizer/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./flow": {
|
|
18
|
+
"types": "./dist/flow/index.d.ts",
|
|
19
|
+
"import": "./dist/flow/index.mjs",
|
|
20
|
+
"require": "./dist/flow/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./monitor": {
|
|
23
|
+
"types": "./dist/monitor/index.d.ts",
|
|
24
|
+
"import": "./dist/monitor/index.mjs",
|
|
25
|
+
"require": "./dist/monitor/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"module": "./dist/index.mjs",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"dev": "tsup --watch",
|
|
38
|
+
"build": "tsup",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"test:watch": "vitest",
|
|
41
|
+
"test:coverage": "vitest run --coverage",
|
|
42
|
+
"lint": "biome check .",
|
|
43
|
+
"lint:fix": "biome check --write .",
|
|
44
|
+
"format": "biome format --write .",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"prepublishOnly": "npm run build && npm run test && npm run typecheck",
|
|
47
|
+
"changeset": "changeset",
|
|
48
|
+
"version": "changeset version",
|
|
49
|
+
"release": "npm run build && changeset publish"
|
|
50
|
+
},
|
|
51
|
+
"keywords": [
|
|
52
|
+
"voice-ai",
|
|
53
|
+
"tts",
|
|
54
|
+
"llm",
|
|
55
|
+
"streaming",
|
|
56
|
+
"speech",
|
|
57
|
+
"conversational-ai",
|
|
58
|
+
"realtime",
|
|
59
|
+
"latency",
|
|
60
|
+
"voice-agents",
|
|
61
|
+
"text-to-speech",
|
|
62
|
+
"ai-agents",
|
|
63
|
+
"openai",
|
|
64
|
+
"elevenlabs"
|
|
65
|
+
],
|
|
66
|
+
"author": "",
|
|
67
|
+
"license": "MIT",
|
|
68
|
+
"repository": {
|
|
69
|
+
"type": "git",
|
|
70
|
+
"url": ""
|
|
71
|
+
},
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": ""
|
|
74
|
+
},
|
|
75
|
+
"homepage": "",
|
|
76
|
+
"engines": {
|
|
77
|
+
"node": ">=18.0.0"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@biomejs/biome": "^1.9.4",
|
|
81
|
+
"@changesets/cli": "^2.27.10",
|
|
82
|
+
"@types/node": "^22.10.5",
|
|
83
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
84
|
+
"tsup": "^8.3.5",
|
|
85
|
+
"typescript": "^5.7.2",
|
|
86
|
+
"vitest": "^2.1.8"
|
|
87
|
+
},
|
|
88
|
+
"peerDependencies": {},
|
|
89
|
+
"dependencies": {}
|
|
90
|
+
}
|