Rewrite frontend as single self-contained HTML file — all CSS/JS inline, no external files to fail loading
This commit is contained in:
8
dist/providers/tts/elevenLabsTTSProvider.d.ts
vendored
Normal file
8
dist/providers/tts/elevenLabsTTSProvider.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { TTSProvider, TTSProviderConfig, TTSOptions, TTSResult } from '../../interfaces';
|
||||
export declare class ElevenLabsTTSProvider implements TTSProvider {
|
||||
private config;
|
||||
private axiosInstance;
|
||||
private lastRequestId;
|
||||
constructor(config: TTSProviderConfig);
|
||||
textToSpeech(text: string, outputPath: string, options?: TTSOptions): Promise<TTSResult>;
|
||||
}
|
||||
79
dist/providers/tts/elevenLabsTTSProvider.js
vendored
Normal file
79
dist/providers/tts/elevenLabsTTSProvider.js
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ElevenLabsTTSProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const child_process_1 = require("child_process");
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
const mediaUtils_1 = require("../../utils/mediaUtils");
|
||||
class ElevenLabsTTSProvider {
|
||||
constructor(config) {
|
||||
this.lastRequestId = null;
|
||||
this.config = config;
|
||||
this.axiosInstance = axios_1.default.create({
|
||||
baseURL: 'https://api.elevenlabs.io/v1',
|
||||
headers: {
|
||||
'xi-api-key': config.apiKey,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
async textToSpeech(text, outputPath, options = {}) {
|
||||
try {
|
||||
const voice = options.voice || this.config.voice || 'JBFqnCBsd6RMkjVDRZzb';
|
||||
const model = options.model || this.config.model || 'eleven_multilingual_v2';
|
||||
const speedFactor = options.speedFactor || 1.0;
|
||||
const requestBody = {
|
||||
text,
|
||||
model_id: model,
|
||||
voice_settings: {
|
||||
stability: 0.5,
|
||||
similarity_boost: 0.75,
|
||||
speed: speedFactor,
|
||||
use_speaker_boost: true
|
||||
}
|
||||
};
|
||||
if (this.lastRequestId) {
|
||||
requestBody.previous_request_ids = [this.lastRequestId];
|
||||
}
|
||||
const tempOutputPath = outputPath.replace(/\.\w+$/, '_temp$&');
|
||||
const response = await this.axiosInstance.post(`/text-to-speech/${voice}`, requestBody, {
|
||||
params: { output_format: 'mp3_44100_128' },
|
||||
responseType: 'arraybuffer'
|
||||
});
|
||||
this.lastRequestId = response.headers['request-id'] || null;
|
||||
const audioBuffer = Buffer.from(response.data);
|
||||
fs_1.default.writeFileSync(tempOutputPath, audioBuffer);
|
||||
const cost = text.length;
|
||||
if (speedFactor !== 1.0) {
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -i "${tempOutputPath}" -filter:a "atempo=${speedFactor}" -c:a libmp3lame -q:a 2 "${outputPath}" -y`);
|
||||
fs_1.default.unlinkSync(tempOutputPath);
|
||||
}
|
||||
else {
|
||||
fs_1.default.renameSync(tempOutputPath, outputPath);
|
||||
}
|
||||
const audioDuration = (0, mediaUtils_1.getAudioDuration)(outputPath);
|
||||
return {
|
||||
duration: audioDuration,
|
||||
cost: cost
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
if (error.response) {
|
||||
console.error(`ElevenLabs TTS error (${error.response.status}):`, Buffer.from(error.response.data).toString());
|
||||
}
|
||||
else {
|
||||
console.error('ElevenLabs TTS error:', error.message);
|
||||
}
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -f lavfi -i anullsrc=r=24000:cl=mono -t 1 -q:a 9 -acodec libmp3lame "${outputPath}" -y`);
|
||||
return {
|
||||
duration: 1,
|
||||
cost: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.ElevenLabsTTSProvider = ElevenLabsTTSProvider;
|
||||
//# sourceMappingURL=elevenLabsTTSProvider.js.map
|
||||
1
dist/providers/tts/elevenLabsTTSProvider.js.map
vendored
Normal file
1
dist/providers/tts/elevenLabsTTSProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"elevenLabsTTSProvider.js","sourceRoot":"","sources":["../../../src/providers/tts/elevenLabsTTSProvider.ts"],"names":[],"mappings":"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"}
|
||||
8
dist/providers/tts/googleCloudTTSProvider.d.ts
vendored
Normal file
8
dist/providers/tts/googleCloudTTSProvider.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { TTSProvider, TTSProviderConfig, TTSOptions, TTSResult } from '../../interfaces';
|
||||
export declare class GoogleCloudTTSProvider implements TTSProvider {
|
||||
private config;
|
||||
private client;
|
||||
constructor(config: TTSProviderConfig);
|
||||
textToSpeech(text: string, outputPath: string, options?: TTSOptions): Promise<TTSResult>;
|
||||
private extractLanguageCode;
|
||||
}
|
||||
80
dist/providers/tts/googleCloudTTSProvider.js
vendored
Normal file
80
dist/providers/tts/googleCloudTTSProvider.js
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GoogleCloudTTSProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const child_process_1 = require("child_process");
|
||||
const text_to_speech_1 = require("@google-cloud/text-to-speech");
|
||||
const mediaUtils_1 = require("../../utils/mediaUtils");
|
||||
class GoogleCloudTTSProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
const clientConfig = {
|
||||
apiKey: config.apiKey,
|
||||
fallback: true
|
||||
};
|
||||
if (config.keyFilename) {
|
||||
clientConfig.keyFilename = config.keyFilename;
|
||||
}
|
||||
this.client = new text_to_speech_1.TextToSpeechClient(clientConfig);
|
||||
}
|
||||
async textToSpeech(text, outputPath, options = {}) {
|
||||
try {
|
||||
const voice = options.voice || this.config.voice || 'en-US-Chirp-HD-F';
|
||||
const model = options.model || this.config.model || 'chirp-hd';
|
||||
const speedFactor = options.speedFactor || 1.0;
|
||||
const request = {
|
||||
input: { text },
|
||||
voice: {
|
||||
languageCode: this.extractLanguageCode(voice),
|
||||
name: voice
|
||||
},
|
||||
audioConfig: {
|
||||
audioEncoding: 'MP3',
|
||||
speakingRate: speedFactor
|
||||
}
|
||||
};
|
||||
const [response] = await this.client.synthesizeSpeech(request);
|
||||
if (!response.audioContent) {
|
||||
throw new Error('No audio content returned from Google Cloud TTS');
|
||||
}
|
||||
const audioBuffer = response.audioContent instanceof Uint8Array
|
||||
? Buffer.from(response.audioContent)
|
||||
: Buffer.from(response.audioContent);
|
||||
const tempOutputPath = outputPath.replace(/\.\w+$/, '_temp$&');
|
||||
fs_1.default.writeFileSync(tempOutputPath, audioBuffer);
|
||||
const cost = text.length;
|
||||
if (speedFactor !== 1.0) {
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -i "${tempOutputPath}" -filter:a "atempo=${speedFactor}" -c:a libmp3lame -q:a 2 "${outputPath}" -y`);
|
||||
fs_1.default.unlinkSync(tempOutputPath);
|
||||
}
|
||||
else {
|
||||
fs_1.default.renameSync(tempOutputPath, outputPath);
|
||||
}
|
||||
const audioDuration = (0, mediaUtils_1.getAudioDuration)(outputPath);
|
||||
return {
|
||||
duration: audioDuration,
|
||||
cost: cost
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Google Cloud TTS error:', error.message);
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -f lavfi -i anullsrc=r=24000:cl=mono -t 1 -q:a 9 -acodec libmp3lame "${outputPath}" -y`);
|
||||
return {
|
||||
duration: 1,
|
||||
cost: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
extractLanguageCode(voiceName) {
|
||||
const parts = voiceName.split('-');
|
||||
if (parts.length >= 2) {
|
||||
return `${parts[0]}-${parts[1]}`;
|
||||
}
|
||||
return 'en-US';
|
||||
}
|
||||
}
|
||||
exports.GoogleCloudTTSProvider = GoogleCloudTTSProvider;
|
||||
//# sourceMappingURL=googleCloudTTSProvider.js.map
|
||||
1
dist/providers/tts/googleCloudTTSProvider.js.map
vendored
Normal file
1
dist/providers/tts/googleCloudTTSProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"googleCloudTTSProvider.js","sourceRoot":"","sources":["../../../src/providers/tts/googleCloudTTSProvider.ts"],"names":[],"mappings":"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"}
|
||||
4
dist/providers/tts/index.d.ts
vendored
Normal file
4
dist/providers/tts/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './ttsProviderFactory';
|
||||
export * from './openAITTSProvider';
|
||||
export * from './elevenLabsTTSProvider';
|
||||
export * from './googleCloudTTSProvider';
|
||||
21
dist/providers/tts/index.js
vendored
Normal file
21
dist/providers/tts/index.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./ttsProviderFactory"), exports);
|
||||
__exportStar(require("./openAITTSProvider"), exports);
|
||||
__exportStar(require("./elevenLabsTTSProvider"), exports);
|
||||
__exportStar(require("./googleCloudTTSProvider"), exports);
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
dist/providers/tts/index.js.map
vendored
Normal file
1
dist/providers/tts/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/tts/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,sDAAoC;AACpC,0DAAwC;AACxC,2DAAyC"}
|
||||
17
dist/providers/tts/openAITTSProvider.d.ts
vendored
Normal file
17
dist/providers/tts/openAITTSProvider.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { TTSProvider, TTSProviderConfig, TTSOptions, TTSResult } from '../../interfaces';
|
||||
/**
|
||||
* OpenAI TTS Provider Implementation
|
||||
*/
|
||||
export declare class OpenAITTSProvider implements TTSProvider {
|
||||
private config;
|
||||
private openai;
|
||||
constructor(config: TTSProviderConfig);
|
||||
/**
|
||||
* Convert text to speech
|
||||
* @param text - Text to convert to speech
|
||||
* @param outputPath - Output path for the audio file
|
||||
* @param options - Additional options
|
||||
* @returns Duration of the generated audio in seconds and cost
|
||||
*/
|
||||
textToSpeech(text: string, outputPath: string, options?: TTSOptions): Promise<TTSResult>;
|
||||
}
|
||||
75
dist/providers/tts/openAITTSProvider.js
vendored
Normal file
75
dist/providers/tts/openAITTSProvider.js
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OpenAITTSProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const child_process_1 = require("child_process");
|
||||
const openai_1 = require("openai");
|
||||
const mediaUtils_1 = require("../../utils/mediaUtils");
|
||||
/**
|
||||
* OpenAI TTS Provider Implementation
|
||||
*/
|
||||
class OpenAITTSProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.openai = new openai_1.OpenAI({
|
||||
apiKey: config.apiKey,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Convert text to speech
|
||||
* @param text - Text to convert to speech
|
||||
* @param outputPath - Output path for the audio file
|
||||
* @param options - Additional options
|
||||
* @returns Duration of the generated audio in seconds and cost
|
||||
*/
|
||||
async textToSpeech(text, outputPath, options = {}) {
|
||||
try {
|
||||
// Get the options, with defaults from config
|
||||
const voice = options.voice || this.config.voice;
|
||||
const model = options.model || this.config.model;
|
||||
const speedFactor = options.speedFactor || 1.0;
|
||||
// Generate the initial TTS output
|
||||
const tempOutputPath = outputPath.replace(/\.\w+$/, '_temp$&');
|
||||
const mp3 = await this.openai.audio.speech.create({
|
||||
model: model,
|
||||
voice: voice,
|
||||
input: text,
|
||||
...(options.instructions ? { instructions: options.instructions } : {})
|
||||
});
|
||||
// Cost calculation is based on character count
|
||||
const cost = text.length;
|
||||
const buffer = Buffer.from(await mp3.arrayBuffer());
|
||||
fs_1.default.writeFileSync(tempOutputPath, buffer);
|
||||
// Speed up the audio using FFmpeg if needed
|
||||
if (speedFactor !== 1.0) {
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -i "${tempOutputPath}" -filter:a "atempo=${speedFactor}" -c:a libmp3lame -q:a 2 "${outputPath}" -y`);
|
||||
// Clean up temporary file
|
||||
fs_1.default.unlinkSync(tempOutputPath);
|
||||
}
|
||||
else {
|
||||
// Just use the file as is
|
||||
fs_1.default.renameSync(tempOutputPath, outputPath);
|
||||
}
|
||||
// Get actual audio duration for accurate timing
|
||||
const audioDuration = (0, mediaUtils_1.getAudioDuration)(outputPath);
|
||||
return {
|
||||
duration: audioDuration,
|
||||
cost: cost
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error generating speech:", error);
|
||||
// Create a silent audio file if TTS fails
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -f lavfi -i anullsrc=r=24000:cl=mono -t 1 -q:a 9 -acodec libmp3lame "${outputPath}" -y`);
|
||||
return {
|
||||
duration: 1,
|
||||
cost: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.OpenAITTSProvider = OpenAITTSProvider;
|
||||
//# sourceMappingURL=openAITTSProvider.js.map
|
||||
1
dist/providers/tts/openAITTSProvider.js.map
vendored
Normal file
1
dist/providers/tts/openAITTSProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"openAITTSProvider.js","sourceRoot":"","sources":["../../../src/providers/tts/openAITTSProvider.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,iDAAyC;AACzC,mCAAgC;AAEhC,uDAA0D;AAE1D;;GAEG;AACH,MAAa,iBAAiB;IAI5B,YAAY,MAAyB;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,CAAC;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,YAAY,CAChB,IAAY,EACZ,UAAkB,EAClB,UAAsB,EAAE;QAExB,IAAI,CAAC;YACH,6CAA6C;YAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACjD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACjD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC;YAE/C,kCAAkC;YAClC,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAE/D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;gBAChD,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,KAAY;gBACnB,KAAK,EAAE,IAAI;gBACX,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACxE,CAAC,CAAC;YAEH,+CAA+C;YAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;YAEzB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;YACpD,YAAE,CAAC,aAAa,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;YAEzC,4CAA4C;YAC5C,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;gBACxB,IAAA,wBAAQ,EAAC,uBAAuB,cAAc,uBAAuB,WAAW,6BAA6B,UAAU,MAAM,CAAC,CAAC;gBAC/H,0BAA0B;gBAC1B,YAAE,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,0BAA0B;gBAC1B,YAAE,CAAC,UAAU,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;YAC5C,CAAC;YAED,gDAAgD;YAChD,MAAM,aAAa,GAAG,IAAA,6BAAgB,EAAC,UAAU,CAAC,CAAC;YAEnD,OAAO;gBACL,QAAQ,EAAE,aAAa;gBACvB,IAAI,EAAE,IAAI;aACX,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,0CAA0C;YAC1C,IAAA,wBAAQ,EAAC,wFAAwF,UAAU,MAAM,CAAC,CAAC;YACnH,OAAO;gBACL,QAAQ,EAAE,CAAC;gBACX,IAAI,EAAE,CAAC;aACR,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AAxED,8CAwEC"}
|
||||
8
dist/providers/tts/ttsProviderFactory.d.ts
vendored
Normal file
8
dist/providers/tts/ttsProviderFactory.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { TTSProvider } from '../../interfaces';
|
||||
import { Config } from '../../config/config';
|
||||
/**
|
||||
* Factory for creating TTS providers
|
||||
*/
|
||||
export declare class TTSProviderFactory {
|
||||
static getProvider(config: Config): TTSProvider;
|
||||
}
|
||||
31
dist/providers/tts/ttsProviderFactory.js
vendored
Normal file
31
dist/providers/tts/ttsProviderFactory.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TTSProviderFactory = void 0;
|
||||
const openAITTSProvider_1 = require("./openAITTSProvider");
|
||||
const elevenLabsTTSProvider_1 = require("./elevenLabsTTSProvider");
|
||||
const googleCloudTTSProvider_1 = require("./googleCloudTTSProvider");
|
||||
/**
|
||||
* Factory for creating TTS providers
|
||||
*/
|
||||
class TTSProviderFactory {
|
||||
static getProvider(config) {
|
||||
const providerName = config.ttsProvider;
|
||||
const providerConfig = config.ttsProviders[providerName];
|
||||
if (!providerConfig) {
|
||||
throw new Error(`TTS provider "${providerName}" not configured.`);
|
||||
}
|
||||
switch (providerName) {
|
||||
case 'openai':
|
||||
return new openAITTSProvider_1.OpenAITTSProvider(providerConfig);
|
||||
case 'elevenlabs':
|
||||
return new elevenLabsTTSProvider_1.ElevenLabsTTSProvider(providerConfig);
|
||||
case 'google':
|
||||
return new googleCloudTTSProvider_1.GoogleCloudTTSProvider(providerConfig);
|
||||
// Add other providers here
|
||||
default:
|
||||
throw new Error(`TTS provider "${providerName}" not implemented.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.TTSProviderFactory = TTSProviderFactory;
|
||||
//# sourceMappingURL=ttsProviderFactory.js.map
|
||||
1
dist/providers/tts/ttsProviderFactory.js.map
vendored
Normal file
1
dist/providers/tts/ttsProviderFactory.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ttsProviderFactory.js","sourceRoot":"","sources":["../../../src/providers/tts/ttsProviderFactory.ts"],"names":[],"mappings":";;;AAEA,2DAAwD;AACxD,mEAAgE;AAChE,qEAAkE;AAElE;;GAEG;AACH,MAAa,kBAAkB;IAC7B,MAAM,CAAC,WAAW,CAAC,MAAc;QAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC;QACxC,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QAEzD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,iBAAiB,YAAY,mBAAmB,CAAC,CAAC;QACpE,CAAC;QAED,QAAQ,YAAY,EAAE,CAAC;YACrB,KAAK,QAAQ;gBACX,OAAO,IAAI,qCAAiB,CAAC,cAAc,CAAC,CAAC;YAC/C,KAAK,YAAY;gBACf,OAAO,IAAI,6CAAqB,CAAC,cAAc,CAAC,CAAC;YACnD,KAAK,QAAQ;gBACX,OAAO,IAAI,+CAAsB,CAAC,cAAc,CAAC,CAAC;YACpD,2BAA2B;YAC3B;gBACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,YAAY,oBAAoB,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;CACF;AArBD,gDAqBC"}
|
||||
Reference in New Issue
Block a user