@juspay/neurolink 8.35.2 → 8.37.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/CHANGELOG.md +12 -0
- package/dist/lib/types/generateTypes.d.ts +34 -2
- package/dist/lib/types/pptTypes.d.ts +69 -0
- package/dist/lib/types/pptTypes.js +2 -0
- package/dist/lib/utils/errorHandling.d.ts +60 -0
- package/dist/lib/utils/errorHandling.js +237 -0
- package/dist/lib/utils/imageProcessor.d.ts +1 -0
- package/dist/lib/utils/imageProcessor.js +4 -0
- package/dist/lib/utils/messageBuilder.js +4 -0
- package/dist/lib/utils/parameterValidation.d.ts +41 -0
- package/dist/lib/utils/parameterValidation.js +226 -0
- package/dist/lib/utils/rateLimiter.d.ts +89 -0
- package/dist/lib/utils/rateLimiter.js +201 -0
- package/dist/types/generateTypes.d.ts +34 -2
- package/dist/types/pptTypes.d.ts +69 -0
- package/dist/types/pptTypes.js +1 -0
- package/dist/utils/errorHandling.d.ts +60 -0
- package/dist/utils/errorHandling.js +237 -0
- package/dist/utils/imageProcessor.d.ts +1 -0
- package/dist/utils/imageProcessor.js +4 -0
- package/dist/utils/messageBuilder.js +4 -0
- package/dist/utils/parameterValidation.d.ts +41 -0
- package/dist/utils/parameterValidation.js +226 -0
- package/dist/utils/rateLimiter.d.ts +89 -0
- package/dist/utils/rateLimiter.js +200 -0
- package/package.json +1 -1
|
@@ -32,6 +32,18 @@ export declare const ERROR_CODES: {
|
|
|
32
32
|
readonly IMAGE_TOO_LARGE: "IMAGE_TOO_LARGE";
|
|
33
33
|
readonly IMAGE_TOO_SMALL: "IMAGE_TOO_SMALL";
|
|
34
34
|
readonly INVALID_IMAGE_FORMAT: "INVALID_IMAGE_FORMAT";
|
|
35
|
+
readonly RATE_LIMITER_QUEUE_FULL: "RATE_LIMITER_QUEUE_FULL";
|
|
36
|
+
readonly RATE_LIMITER_QUEUE_TIMEOUT: "RATE_LIMITER_QUEUE_TIMEOUT";
|
|
37
|
+
readonly RATE_LIMITER_RESET: "RATE_LIMITER_RESET";
|
|
38
|
+
readonly MISSING_PPT_PROPERTIES: "MISSING_PPT_PROPERTIES";
|
|
39
|
+
readonly INVALID_PPT_PAGES: "INVALID_PPT_PAGES";
|
|
40
|
+
readonly INVALID_PPT_FORMAT: "INVALID_PPT_FORMAT";
|
|
41
|
+
readonly INVALID_PPT_PROVIDER: "INVALID_PPT_PROVIDER";
|
|
42
|
+
readonly INVALID_PPT_OUTPUT_OPTIONS: "INVALID_PPT_OUTPUT_OPTIONS";
|
|
43
|
+
readonly INVALID_PPT_OUTPUT_PATH: "INVALID_PPT_OUTPUT_PATH";
|
|
44
|
+
readonly INVALID_PPT_LOGO_PATH: "INVALID_PPT_LOGO_PATH";
|
|
45
|
+
readonly INVALID_PPT_MODE: "INVALID_PPT_MODE";
|
|
46
|
+
readonly INVALID_PPT_PROMPT: "INVALID_PPT_PROMPT";
|
|
35
47
|
};
|
|
36
48
|
/**
|
|
37
49
|
* Enhanced error class with structured information
|
|
@@ -149,6 +161,54 @@ export declare class ErrorFactory {
|
|
|
149
161
|
* Create an invalid image format error
|
|
150
162
|
*/
|
|
151
163
|
static invalidImageFormat(): NeuroLinkError;
|
|
164
|
+
/**
|
|
165
|
+
* Create a rate limiter queue full error
|
|
166
|
+
*/
|
|
167
|
+
static rateLimiterQueueFull(maxQueueSize: number): NeuroLinkError;
|
|
168
|
+
/**
|
|
169
|
+
* Create a rate limiter queue timeout error
|
|
170
|
+
*/
|
|
171
|
+
static rateLimiterQueueTimeout(timeoutMs: number): NeuroLinkError;
|
|
172
|
+
/**
|
|
173
|
+
* Create a rate limiter reset error
|
|
174
|
+
*/
|
|
175
|
+
static rateLimiterReset(): NeuroLinkError;
|
|
176
|
+
/**
|
|
177
|
+
* Create a generic missing PPT property error
|
|
178
|
+
*/
|
|
179
|
+
static missingPPTProperty(field: string, suggestions?: string[]): NeuroLinkError;
|
|
180
|
+
/**
|
|
181
|
+
* Create an invalid PPT pages error
|
|
182
|
+
*/
|
|
183
|
+
static invalidPPTPages(pages: unknown, reason: string): NeuroLinkError;
|
|
184
|
+
/**
|
|
185
|
+
* Create an invalid PPT format error
|
|
186
|
+
*/
|
|
187
|
+
static invalidPPTFormat(format: string): NeuroLinkError;
|
|
188
|
+
/**
|
|
189
|
+
* Create a generic invalid PPT output options error
|
|
190
|
+
*/
|
|
191
|
+
static invalidPPTOutputOptions(field: string, value: unknown, validOptions?: string[]): NeuroLinkError;
|
|
192
|
+
/**
|
|
193
|
+
* Create an invalid PPT output path error
|
|
194
|
+
*/
|
|
195
|
+
static invalidPPTOutputPath(path: unknown, reason: string): NeuroLinkError;
|
|
196
|
+
/**
|
|
197
|
+
* Create an invalid PPT mode error
|
|
198
|
+
*/
|
|
199
|
+
static invalidPPTMode(): NeuroLinkError;
|
|
200
|
+
/**
|
|
201
|
+
* Create an invalid PPT prompt error
|
|
202
|
+
*/
|
|
203
|
+
static invalidPPTPrompt(reason: string): NeuroLinkError;
|
|
204
|
+
/**
|
|
205
|
+
* Create an invalid PPT logo path error
|
|
206
|
+
*/
|
|
207
|
+
static invalidPPTLogoPath(path: unknown, reason: string): NeuroLinkError;
|
|
208
|
+
/**
|
|
209
|
+
* Create an invalid PPT provider error
|
|
210
|
+
*/
|
|
211
|
+
static invalidPPTProvider(provider: unknown): NeuroLinkError;
|
|
152
212
|
}
|
|
153
213
|
/**
|
|
154
214
|
* Timeout wrapper for async operations
|
|
@@ -40,6 +40,20 @@ export const ERROR_CODES = {
|
|
|
40
40
|
IMAGE_TOO_LARGE: "IMAGE_TOO_LARGE",
|
|
41
41
|
IMAGE_TOO_SMALL: "IMAGE_TOO_SMALL",
|
|
42
42
|
INVALID_IMAGE_FORMAT: "INVALID_IMAGE_FORMAT",
|
|
43
|
+
// Rate limiter errors
|
|
44
|
+
RATE_LIMITER_QUEUE_FULL: "RATE_LIMITER_QUEUE_FULL",
|
|
45
|
+
RATE_LIMITER_QUEUE_TIMEOUT: "RATE_LIMITER_QUEUE_TIMEOUT",
|
|
46
|
+
RATE_LIMITER_RESET: "RATE_LIMITER_RESET",
|
|
47
|
+
// PPT validation errors
|
|
48
|
+
MISSING_PPT_PROPERTIES: "MISSING_PPT_PROPERTIES",
|
|
49
|
+
INVALID_PPT_PAGES: "INVALID_PPT_PAGES",
|
|
50
|
+
INVALID_PPT_FORMAT: "INVALID_PPT_FORMAT",
|
|
51
|
+
INVALID_PPT_PROVIDER: "INVALID_PPT_PROVIDER",
|
|
52
|
+
INVALID_PPT_OUTPUT_OPTIONS: "INVALID_PPT_OUTPUT_OPTIONS",
|
|
53
|
+
INVALID_PPT_OUTPUT_PATH: "INVALID_PPT_OUTPUT_PATH",
|
|
54
|
+
INVALID_PPT_LOGO_PATH: "INVALID_PPT_LOGO_PATH",
|
|
55
|
+
INVALID_PPT_MODE: "INVALID_PPT_MODE",
|
|
56
|
+
INVALID_PPT_PROMPT: "INVALID_PPT_PROMPT",
|
|
43
57
|
};
|
|
44
58
|
/**
|
|
45
59
|
* Enhanced error class with structured information
|
|
@@ -461,6 +475,229 @@ export class ErrorFactory {
|
|
|
461
475
|
},
|
|
462
476
|
});
|
|
463
477
|
}
|
|
478
|
+
// ============================================================================
|
|
479
|
+
// RATE LIMITER ERRORS
|
|
480
|
+
// ============================================================================
|
|
481
|
+
/**
|
|
482
|
+
* Create a rate limiter queue full error
|
|
483
|
+
*/
|
|
484
|
+
static rateLimiterQueueFull(maxQueueSize) {
|
|
485
|
+
return new NeuroLinkError({
|
|
486
|
+
code: ERROR_CODES.RATE_LIMITER_QUEUE_FULL,
|
|
487
|
+
message: `Rate limiter queue full: too many pending requests (${maxQueueSize} max)`,
|
|
488
|
+
category: ErrorCategory.RESOURCE,
|
|
489
|
+
severity: ErrorSeverity.HIGH,
|
|
490
|
+
retriable: true,
|
|
491
|
+
context: { maxQueueSize },
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Create a rate limiter queue timeout error
|
|
496
|
+
*/
|
|
497
|
+
static rateLimiterQueueTimeout(timeoutMs) {
|
|
498
|
+
return new NeuroLinkError({
|
|
499
|
+
code: ERROR_CODES.RATE_LIMITER_QUEUE_TIMEOUT,
|
|
500
|
+
message: `Rate limiter queue timeout: request exceeded ${timeoutMs}ms wait time`,
|
|
501
|
+
category: ErrorCategory.TIMEOUT,
|
|
502
|
+
severity: ErrorSeverity.HIGH,
|
|
503
|
+
retriable: true,
|
|
504
|
+
context: { timeoutMs },
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Create a rate limiter reset error
|
|
509
|
+
*/
|
|
510
|
+
static rateLimiterReset() {
|
|
511
|
+
return new NeuroLinkError({
|
|
512
|
+
code: ERROR_CODES.RATE_LIMITER_RESET,
|
|
513
|
+
message: "Rate limiter was reset while request was pending",
|
|
514
|
+
category: ErrorCategory.EXECUTION,
|
|
515
|
+
severity: ErrorSeverity.MEDIUM,
|
|
516
|
+
retriable: true,
|
|
517
|
+
context: {},
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
// ============================================================================
|
|
521
|
+
// PPT VALIDATION ERRORS
|
|
522
|
+
// ============================================================================
|
|
523
|
+
/**
|
|
524
|
+
* Create a generic missing PPT property error
|
|
525
|
+
*/
|
|
526
|
+
static missingPPTProperty(field, suggestions) {
|
|
527
|
+
const defaultSuggestions = [`Provide the required '${field}' field`];
|
|
528
|
+
return new NeuroLinkError({
|
|
529
|
+
code: ERROR_CODES.MISSING_PPT_PROPERTIES,
|
|
530
|
+
message: `PPT generation requires '${field}' field`,
|
|
531
|
+
category: ErrorCategory.VALIDATION,
|
|
532
|
+
severity: ErrorSeverity.MEDIUM,
|
|
533
|
+
retriable: false,
|
|
534
|
+
context: {
|
|
535
|
+
field,
|
|
536
|
+
suggestions: suggestions || defaultSuggestions,
|
|
537
|
+
},
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Create an invalid PPT pages error
|
|
542
|
+
*/
|
|
543
|
+
static invalidPPTPages(pages, reason) {
|
|
544
|
+
return new NeuroLinkError({
|
|
545
|
+
code: ERROR_CODES.INVALID_PPT_PAGES,
|
|
546
|
+
message: `Invalid pages value '${pages}': ${reason}`,
|
|
547
|
+
category: ErrorCategory.VALIDATION,
|
|
548
|
+
severity: ErrorSeverity.MEDIUM,
|
|
549
|
+
retriable: false,
|
|
550
|
+
context: {
|
|
551
|
+
field: "output.ppt.pages",
|
|
552
|
+
providedValue: pages,
|
|
553
|
+
suggestions: [
|
|
554
|
+
"Use a number between 5 and 50",
|
|
555
|
+
"For longer presentations, consider breaking into multiple decks",
|
|
556
|
+
],
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Create an invalid PPT format error
|
|
562
|
+
*/
|
|
563
|
+
static invalidPPTFormat(format) {
|
|
564
|
+
return new NeuroLinkError({
|
|
565
|
+
code: ERROR_CODES.INVALID_PPT_FORMAT,
|
|
566
|
+
message: `Invalid format '${format}'. Only 'pptx' is supported`,
|
|
567
|
+
category: ErrorCategory.VALIDATION,
|
|
568
|
+
severity: ErrorSeverity.MEDIUM,
|
|
569
|
+
retriable: false,
|
|
570
|
+
context: {
|
|
571
|
+
field: "output.ppt.format",
|
|
572
|
+
providedValue: format,
|
|
573
|
+
suggestions: ["Use format: 'pptx' or omit (defaults to 'pptx')"],
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Create a generic invalid PPT output options error
|
|
579
|
+
*/
|
|
580
|
+
static invalidPPTOutputOptions(field, value, validOptions) {
|
|
581
|
+
const suggestions = validOptions
|
|
582
|
+
? validOptions.map((opt) => `Use '${opt}'`)
|
|
583
|
+
: ["Check the documentation for valid options"];
|
|
584
|
+
return new NeuroLinkError({
|
|
585
|
+
code: ERROR_CODES.INVALID_PPT_OUTPUT_OPTIONS,
|
|
586
|
+
message: `Invalid ${field} value '${value}'`,
|
|
587
|
+
category: ErrorCategory.VALIDATION,
|
|
588
|
+
severity: ErrorSeverity.MEDIUM,
|
|
589
|
+
retriable: false,
|
|
590
|
+
context: {
|
|
591
|
+
field: `output.ppt.${field}`,
|
|
592
|
+
providedValue: value,
|
|
593
|
+
suggestions,
|
|
594
|
+
},
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Create an invalid PPT output path error
|
|
599
|
+
*/
|
|
600
|
+
static invalidPPTOutputPath(path, reason) {
|
|
601
|
+
return new NeuroLinkError({
|
|
602
|
+
code: ERROR_CODES.INVALID_PPT_OUTPUT_PATH,
|
|
603
|
+
message: `Invalid outputPath '${path}': ${reason}`,
|
|
604
|
+
category: ErrorCategory.VALIDATION,
|
|
605
|
+
severity: ErrorSeverity.MEDIUM,
|
|
606
|
+
retriable: false,
|
|
607
|
+
context: {
|
|
608
|
+
field: "output.ppt.outputPath",
|
|
609
|
+
providedValue: path,
|
|
610
|
+
suggestions: [
|
|
611
|
+
"Provide a valid file path string",
|
|
612
|
+
"Example: './presentations/my-deck.pptx'",
|
|
613
|
+
"Omit to use auto-generated path",
|
|
614
|
+
],
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Create an invalid PPT mode error
|
|
620
|
+
*/
|
|
621
|
+
static invalidPPTMode() {
|
|
622
|
+
return new NeuroLinkError({
|
|
623
|
+
code: ERROR_CODES.INVALID_PPT_MODE,
|
|
624
|
+
message: "Presentation generation requires output.mode to be 'ppt'",
|
|
625
|
+
category: ErrorCategory.VALIDATION,
|
|
626
|
+
severity: ErrorSeverity.MEDIUM,
|
|
627
|
+
retriable: false,
|
|
628
|
+
context: {
|
|
629
|
+
field: "output.mode",
|
|
630
|
+
suggestions: [
|
|
631
|
+
"Set output: { mode: 'ppt' } for presentation generation",
|
|
632
|
+
],
|
|
633
|
+
},
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Create an invalid PPT prompt error
|
|
638
|
+
*/
|
|
639
|
+
static invalidPPTPrompt(reason) {
|
|
640
|
+
return new NeuroLinkError({
|
|
641
|
+
code: ERROR_CODES.INVALID_PPT_PROMPT,
|
|
642
|
+
message: `Invalid PPT prompt: ${reason}`,
|
|
643
|
+
category: ErrorCategory.VALIDATION,
|
|
644
|
+
severity: ErrorSeverity.MEDIUM,
|
|
645
|
+
retriable: false,
|
|
646
|
+
context: {
|
|
647
|
+
field: "input.text",
|
|
648
|
+
suggestions: [
|
|
649
|
+
"Provide a non-empty text prompt",
|
|
650
|
+
"Keep the prompt under 1000 characters",
|
|
651
|
+
"Focus on key topics and structure for the presentation",
|
|
652
|
+
],
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Create an invalid PPT logo path error
|
|
658
|
+
*/
|
|
659
|
+
static invalidPPTLogoPath(path, reason) {
|
|
660
|
+
return new NeuroLinkError({
|
|
661
|
+
code: ERROR_CODES.INVALID_PPT_LOGO_PATH,
|
|
662
|
+
message: `Invalid logoPath '${path}': ${reason}`,
|
|
663
|
+
category: ErrorCategory.VALIDATION,
|
|
664
|
+
severity: ErrorSeverity.MEDIUM,
|
|
665
|
+
retriable: false,
|
|
666
|
+
context: {
|
|
667
|
+
field: "output.ppt.logoPath",
|
|
668
|
+
providedValue: path,
|
|
669
|
+
suggestions: [
|
|
670
|
+
"Provide a valid file path string",
|
|
671
|
+
"Example: './assets/logo.png'",
|
|
672
|
+
"Omit to skip logo inclusion",
|
|
673
|
+
],
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Create an invalid PPT provider error
|
|
679
|
+
*/
|
|
680
|
+
static invalidPPTProvider(provider) {
|
|
681
|
+
return new NeuroLinkError({
|
|
682
|
+
code: ERROR_CODES.INVALID_PPT_PROVIDER,
|
|
683
|
+
message: `Invalid provider '${provider}' for PPT generation. Supported providers: vertex, openai, azure, anthropic, google-ai, bedrock`,
|
|
684
|
+
category: ErrorCategory.VALIDATION,
|
|
685
|
+
severity: ErrorSeverity.MEDIUM,
|
|
686
|
+
retriable: false,
|
|
687
|
+
context: {
|
|
688
|
+
field: "provider",
|
|
689
|
+
providedValue: provider,
|
|
690
|
+
suggestions: [
|
|
691
|
+
"Use 'vertex' for Google Vertex AI (Gemini)",
|
|
692
|
+
"Use 'openai' for OpenAI GPT models",
|
|
693
|
+
"Use 'azure' for Azure OpenAI",
|
|
694
|
+
"Use 'anthropic' for Anthropic Claude models",
|
|
695
|
+
"Use 'google-ai' for Google AI Studio (Gemini)",
|
|
696
|
+
"Use 'bedrock' for AWS Bedrock (Claude, Llama, Nova, etc.)",
|
|
697
|
+
],
|
|
698
|
+
},
|
|
699
|
+
});
|
|
700
|
+
}
|
|
464
701
|
}
|
|
465
702
|
/**
|
|
466
703
|
* Timeout wrapper for async operations
|
|
@@ -137,6 +137,7 @@ export declare const imageUtils: {
|
|
|
137
137
|
* @param options.maxBytes - Maximum allowed file size (default: 10MB)
|
|
138
138
|
* @param options.maxAttempts - Maximum number of total attempts including initial attempt (default: 3)
|
|
139
139
|
* @returns Promise<string> - Base64 data URI of the downloaded image
|
|
140
|
+
* Rate-limited to 10 downloads per second to prevent DoS
|
|
140
141
|
*/
|
|
141
142
|
urlToBase64DataUri: (url: string, { timeoutMs, maxBytes, maxAttempts, }?: {
|
|
142
143
|
timeoutMs?: number;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Handles format conversion for different AI providers
|
|
4
4
|
*/
|
|
5
5
|
import { logger } from "./logger.js";
|
|
6
|
+
import { urlDownloadRateLimiter } from "./rateLimiter.js";
|
|
6
7
|
import { withRetry } from "./retryHandler.js";
|
|
7
8
|
import { SYSTEM_LIMITS } from "../core/constants.js";
|
|
8
9
|
/**
|
|
@@ -544,8 +545,11 @@ export const imageUtils = {
|
|
|
544
545
|
* @param options.maxBytes - Maximum allowed file size (default: 10MB)
|
|
545
546
|
* @param options.maxAttempts - Maximum number of total attempts including initial attempt (default: 3)
|
|
546
547
|
* @returns Promise<string> - Base64 data URI of the downloaded image
|
|
548
|
+
* Rate-limited to 10 downloads per second to prevent DoS
|
|
547
549
|
*/
|
|
548
550
|
urlToBase64DataUri: async (url, { timeoutMs = 15000, maxBytes = 10 * 1024 * 1024, maxAttempts = 3, } = {}) => {
|
|
551
|
+
// Apply rate limiting before download
|
|
552
|
+
await urlDownloadRateLimiter.acquire();
|
|
549
553
|
// Basic protocol whitelist - fail fast, no retry needed
|
|
550
554
|
if (!/^https?:\/\//i.test(url)) {
|
|
551
555
|
throw new Error("Unsupported protocol");
|
|
@@ -8,6 +8,7 @@ import { ProviderImageAdapter, MultimodalLogger, } from "../adapters/providerIma
|
|
|
8
8
|
import { logger } from "./logger.js";
|
|
9
9
|
import { FileDetector } from "./fileDetector.js";
|
|
10
10
|
import { PDFProcessor, PDFImageConverter } from "./pdfProcessor.js";
|
|
11
|
+
import { urlDownloadRateLimiter } from "./rateLimiter.js";
|
|
11
12
|
import { request, getGlobalDispatcher, interceptors } from "undici";
|
|
12
13
|
import { readFileSync, existsSync } from "fs";
|
|
13
14
|
/**
|
|
@@ -623,8 +624,11 @@ function isInternetUrl(input) {
|
|
|
623
624
|
}
|
|
624
625
|
/**
|
|
625
626
|
* Download image from URL and convert to base64 data URI
|
|
627
|
+
* Rate-limited to 10 downloads per second to prevent DoS
|
|
626
628
|
*/
|
|
627
629
|
async function downloadImageFromUrl(url) {
|
|
630
|
+
// Apply rate limiting before download
|
|
631
|
+
await urlDownloadRateLimiter.acquire();
|
|
628
632
|
try {
|
|
629
633
|
const response = await request(url, {
|
|
630
634
|
dispatcher: getGlobalDispatcher().compose(interceptors.redirect({ maxRedirections: 5 })),
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { GenerateOptions } from "../types/generateTypes.js";
|
|
6
6
|
import type { VideoOutputOptions } from "../types/multimodal.js";
|
|
7
|
+
import type { PPTOutputOptions } from "../types/pptTypes.js";
|
|
7
8
|
import type { EnhancedValidationResult } from "../types/tools.js";
|
|
8
9
|
import type { StringArray, ValidationSchema } from "../types/typeAliases.js";
|
|
9
10
|
import { NeuroLinkError } from "./errorHandling.js";
|
|
@@ -132,6 +133,46 @@ export declare function validateImageForVideo(image: Buffer | string, maxSize?:
|
|
|
132
133
|
* ```
|
|
133
134
|
*/
|
|
134
135
|
export declare function validateVideoGenerationInput(options: GenerateOptions): EnhancedValidationResult;
|
|
136
|
+
export declare const MIN_PPT_PAGES = 5;
|
|
137
|
+
export declare const MAX_PPT_PAGES = 50;
|
|
138
|
+
export declare const MIN_PPT_PROMPT_LENGTH = 10;
|
|
139
|
+
export declare const MAX_PPT_PROMPT_LENGTH = 1000;
|
|
140
|
+
/**
|
|
141
|
+
* Validate PPT output options (pages, theme, audience, tone, etc.)
|
|
142
|
+
*
|
|
143
|
+
* @param options - PPTOutputOptions to validate
|
|
144
|
+
* @returns NeuroLinkError if invalid, null if valid
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const error = validatePPTOutputOptions({ pages: 100, theme: "invalid" });
|
|
149
|
+
* // error.code === "INVALID_PPT_PAGES"
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export declare function validatePPTOutputOptions(options: PPTOutputOptions): NeuroLinkError | null;
|
|
153
|
+
/**
|
|
154
|
+
* Validate complete PPT generation input
|
|
155
|
+
*
|
|
156
|
+
* Validates all requirements for presentation generation:
|
|
157
|
+
* - output.mode must be "ppt"
|
|
158
|
+
* - Prompt must be within length limits
|
|
159
|
+
* - PPT output options must be valid
|
|
160
|
+
*
|
|
161
|
+
* @param options - GenerateOptions to validate for PPT generation
|
|
162
|
+
* @returns EnhancedValidationResult with errors, warnings, and suggestions
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* const validation = validatePPTGenerationInput({
|
|
167
|
+
* input: { text: "Introducing Our New Product" },
|
|
168
|
+
* output: { mode: "ppt", ppt: { pages: 10, theme: "modern" } }
|
|
169
|
+
* });
|
|
170
|
+
* if (!validation.isValid) {
|
|
171
|
+
* console.error(validation.errors);
|
|
172
|
+
* }
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export declare function validatePPTGenerationInput(options: GenerateOptions): EnhancedValidationResult;
|
|
135
176
|
/**
|
|
136
177
|
* Create a validation error summary for logging
|
|
137
178
|
*/
|
|
@@ -603,6 +603,232 @@ export function validateVideoGenerationInput(options) {
|
|
|
603
603
|
return { isValid: errors.length === 0, errors, warnings, suggestions };
|
|
604
604
|
}
|
|
605
605
|
// ============================================================================
|
|
606
|
+
// PPT VALIDATION (Presentation Generation)
|
|
607
|
+
// ============================================================================
|
|
608
|
+
/**
|
|
609
|
+
* Valid PPT generation options
|
|
610
|
+
*/
|
|
611
|
+
const VALID_PPT_THEMES = [
|
|
612
|
+
"modern",
|
|
613
|
+
"corporate",
|
|
614
|
+
"creative",
|
|
615
|
+
"minimal",
|
|
616
|
+
"dark",
|
|
617
|
+
];
|
|
618
|
+
const VALID_PPT_AUDIENCES = [
|
|
619
|
+
"business",
|
|
620
|
+
"students",
|
|
621
|
+
"technical",
|
|
622
|
+
"general",
|
|
623
|
+
];
|
|
624
|
+
const VALID_PPT_TONES = [
|
|
625
|
+
"professional",
|
|
626
|
+
"casual",
|
|
627
|
+
"educational",
|
|
628
|
+
"persuasive",
|
|
629
|
+
];
|
|
630
|
+
const VALID_PPT_ASPECT_RATIOS = ["16:9", "4:3"];
|
|
631
|
+
const VALID_PPT_FORMATS = ["pptx"];
|
|
632
|
+
export const MIN_PPT_PAGES = 5;
|
|
633
|
+
export const MAX_PPT_PAGES = 50;
|
|
634
|
+
export const MIN_PPT_PROMPT_LENGTH = 10;
|
|
635
|
+
export const MAX_PPT_PROMPT_LENGTH = 1000;
|
|
636
|
+
/**
|
|
637
|
+
* Validate PPT output options (pages, theme, audience, tone, etc.)
|
|
638
|
+
*
|
|
639
|
+
* @param options - PPTOutputOptions to validate
|
|
640
|
+
* @returns NeuroLinkError if invalid, null if valid
|
|
641
|
+
*
|
|
642
|
+
* @example
|
|
643
|
+
* ```typescript
|
|
644
|
+
* const error = validatePPTOutputOptions({ pages: 100, theme: "invalid" });
|
|
645
|
+
* // error.code === "INVALID_PPT_PAGES"
|
|
646
|
+
* ```
|
|
647
|
+
*/
|
|
648
|
+
export function validatePPTOutputOptions(options) {
|
|
649
|
+
// Validate pages (slide count) - REQUIRED FIELD
|
|
650
|
+
if (options.pages === undefined || options.pages === null) {
|
|
651
|
+
return ErrorFactory.missingPPTProperty("output.ppt.pages", [
|
|
652
|
+
"Provide the number of slides: output.ppt.pages = 10",
|
|
653
|
+
"Valid range: 5 to 50 slides",
|
|
654
|
+
"Recommended: 10 slides for most presentations",
|
|
655
|
+
]);
|
|
656
|
+
}
|
|
657
|
+
if (typeof options.pages !== "number") {
|
|
658
|
+
return ErrorFactory.invalidPPTPages(options.pages, "not a number");
|
|
659
|
+
}
|
|
660
|
+
if (!Number.isInteger(options.pages)) {
|
|
661
|
+
return ErrorFactory.invalidPPTPages(options.pages, "not an integer");
|
|
662
|
+
}
|
|
663
|
+
if (options.pages < MIN_PPT_PAGES || options.pages > MAX_PPT_PAGES) {
|
|
664
|
+
return ErrorFactory.invalidPPTPages(options.pages, `out of range (${MIN_PPT_PAGES}-${MAX_PPT_PAGES})`);
|
|
665
|
+
}
|
|
666
|
+
// Validate format
|
|
667
|
+
if (options.format !== undefined &&
|
|
668
|
+
!VALID_PPT_FORMATS.includes(options.format)) {
|
|
669
|
+
return ErrorFactory.invalidPPTFormat(options.format);
|
|
670
|
+
}
|
|
671
|
+
// Validate theme
|
|
672
|
+
if (options.theme !== undefined &&
|
|
673
|
+
!VALID_PPT_THEMES.includes(options.theme)) {
|
|
674
|
+
return ErrorFactory.invalidPPTOutputOptions("theme", options.theme, Array.from(VALID_PPT_THEMES));
|
|
675
|
+
}
|
|
676
|
+
// Validate audience
|
|
677
|
+
if (options.audience !== undefined &&
|
|
678
|
+
!VALID_PPT_AUDIENCES.includes(options.audience)) {
|
|
679
|
+
return ErrorFactory.invalidPPTOutputOptions("audience", options.audience, Array.from(VALID_PPT_AUDIENCES));
|
|
680
|
+
}
|
|
681
|
+
// Validate tone
|
|
682
|
+
if (options.tone !== undefined && !VALID_PPT_TONES.includes(options.tone)) {
|
|
683
|
+
return ErrorFactory.invalidPPTOutputOptions("tone", options.tone, Array.from(VALID_PPT_TONES));
|
|
684
|
+
}
|
|
685
|
+
// Validate aspectRatio
|
|
686
|
+
if (options.aspectRatio !== undefined &&
|
|
687
|
+
!VALID_PPT_ASPECT_RATIOS.includes(options.aspectRatio)) {
|
|
688
|
+
return ErrorFactory.invalidPPTOutputOptions("aspectRatio", options.aspectRatio, Array.from(VALID_PPT_ASPECT_RATIOS));
|
|
689
|
+
}
|
|
690
|
+
// Validate includeImages (must be boolean if provided)
|
|
691
|
+
if (options.includeImages !== undefined &&
|
|
692
|
+
typeof options.includeImages !== "boolean") {
|
|
693
|
+
return ErrorFactory.invalidPPTOutputOptions("includeImages", options.includeImages, ["true", "false"]);
|
|
694
|
+
}
|
|
695
|
+
// Validate logoPath (string path, Buffer, or ImageWithAltText)
|
|
696
|
+
if (options.logoPath !== undefined) {
|
|
697
|
+
if (typeof options.logoPath === "string") {
|
|
698
|
+
if (options.logoPath.trim().length === 0) {
|
|
699
|
+
return ErrorFactory.invalidPPTLogoPath(options.logoPath, "empty string");
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
else if (Buffer.isBuffer(options.logoPath)) {
|
|
703
|
+
// ok
|
|
704
|
+
}
|
|
705
|
+
else if (typeof options.logoPath === "object" &&
|
|
706
|
+
"data" in options.logoPath) {
|
|
707
|
+
const data = options.logoPath.data;
|
|
708
|
+
if (typeof data === "string") {
|
|
709
|
+
if (data.trim().length === 0) {
|
|
710
|
+
return ErrorFactory.invalidPPTLogoPath(options.logoPath, "empty string");
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
else if (!Buffer.isBuffer(data)) {
|
|
714
|
+
return ErrorFactory.invalidPPTLogoPath(options.logoPath, "invalid data type");
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
else {
|
|
718
|
+
return ErrorFactory.invalidPPTLogoPath(options.logoPath, "invalid type");
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
// Validate outputPath (must be non-empty string if provided)
|
|
722
|
+
if (options.outputPath !== undefined) {
|
|
723
|
+
if (typeof options.outputPath !== "string") {
|
|
724
|
+
return ErrorFactory.invalidPPTOutputPath(options.outputPath, "not a string");
|
|
725
|
+
}
|
|
726
|
+
if (options.outputPath.trim().length === 0) {
|
|
727
|
+
return ErrorFactory.invalidPPTOutputPath(options.outputPath, "empty string");
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
function validatePPTProvider(provider) {
|
|
733
|
+
// PPT generation supported providers (subset of all AIProviderName values)
|
|
734
|
+
// Supports major LLM providers with structured output capabilities
|
|
735
|
+
const validProviders = [
|
|
736
|
+
"vertex",
|
|
737
|
+
"openai",
|
|
738
|
+
"azure",
|
|
739
|
+
"anthropic",
|
|
740
|
+
"google-ai",
|
|
741
|
+
"bedrock",
|
|
742
|
+
];
|
|
743
|
+
// Convert enum or string to lowercase string for comparison
|
|
744
|
+
const providerString = String(provider).toLowerCase();
|
|
745
|
+
if (!validProviders.includes(providerString)) {
|
|
746
|
+
return ErrorFactory.invalidPPTProvider(provider);
|
|
747
|
+
}
|
|
748
|
+
return null;
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Validate complete PPT generation input
|
|
752
|
+
*
|
|
753
|
+
* Validates all requirements for presentation generation:
|
|
754
|
+
* - output.mode must be "ppt"
|
|
755
|
+
* - Prompt must be within length limits
|
|
756
|
+
* - PPT output options must be valid
|
|
757
|
+
*
|
|
758
|
+
* @param options - GenerateOptions to validate for PPT generation
|
|
759
|
+
* @returns EnhancedValidationResult with errors, warnings, and suggestions
|
|
760
|
+
*
|
|
761
|
+
* @example
|
|
762
|
+
* ```typescript
|
|
763
|
+
* const validation = validatePPTGenerationInput({
|
|
764
|
+
* input: { text: "Introducing Our New Product" },
|
|
765
|
+
* output: { mode: "ppt", ppt: { pages: 10, theme: "modern" } }
|
|
766
|
+
* });
|
|
767
|
+
* if (!validation.isValid) {
|
|
768
|
+
* console.error(validation.errors);
|
|
769
|
+
* }
|
|
770
|
+
* ```
|
|
771
|
+
*/
|
|
772
|
+
export function validatePPTGenerationInput(options) {
|
|
773
|
+
const errors = [];
|
|
774
|
+
const warnings = [];
|
|
775
|
+
const suggestions = [];
|
|
776
|
+
// Validate prompt/text - trim once for consistency
|
|
777
|
+
const trimmedPrompt = options.input.text.trim();
|
|
778
|
+
if (trimmedPrompt === "") {
|
|
779
|
+
errors.push(toValidationError(ErrorFactory.invalidPPTPrompt("empty prompt")));
|
|
780
|
+
}
|
|
781
|
+
else if (trimmedPrompt.length < MIN_PPT_PROMPT_LENGTH) {
|
|
782
|
+
errors.push(toValidationError(ErrorFactory.invalidPPTPrompt(`prompt too short (${trimmedPrompt.length} characters, min ${MIN_PPT_PROMPT_LENGTH})`)));
|
|
783
|
+
}
|
|
784
|
+
else if (trimmedPrompt.length > MAX_PPT_PROMPT_LENGTH) {
|
|
785
|
+
errors.push(toValidationError(ErrorFactory.invalidPPTPrompt(`prompt too long (${trimmedPrompt.length} characters, max ${MAX_PPT_PROMPT_LENGTH})`)));
|
|
786
|
+
}
|
|
787
|
+
// image PPT options if provided
|
|
788
|
+
if (options.input.images && options.input.images.length > 0) {
|
|
789
|
+
warnings.push("Images can be unused in PPT generation due to fail in quality standards and can lead to longer generation times.");
|
|
790
|
+
suggestions.push("Only provide high-quality, relevant images for PPT generation.");
|
|
791
|
+
}
|
|
792
|
+
// Validate provider (optional - only validate if explicitly provided)
|
|
793
|
+
if (options.provider !== undefined) {
|
|
794
|
+
const providerError = validatePPTProvider(options.provider);
|
|
795
|
+
if (providerError) {
|
|
796
|
+
errors.push(toValidationError(providerError));
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
// Mode is optional, but if provided must be "ppt"
|
|
800
|
+
if (options.output?.mode !== undefined && options.output.mode !== "ppt") {
|
|
801
|
+
errors.push(toValidationError(ErrorFactory.invalidPPTMode()));
|
|
802
|
+
}
|
|
803
|
+
// Validate PPT output options
|
|
804
|
+
if (options.output?.ppt) {
|
|
805
|
+
const pptError = validatePPTOutputOptions(options.output.ppt);
|
|
806
|
+
if (pptError) {
|
|
807
|
+
errors.push(toValidationError(pptError));
|
|
808
|
+
}
|
|
809
|
+
// Add specific warnings
|
|
810
|
+
const pages = options.output.ppt.pages;
|
|
811
|
+
if (pages > 30) {
|
|
812
|
+
warnings.push(`Generating ${pages} slides may take significant time (estimated: ${Math.ceil(pages * 3)}-${Math.ceil(pages * 5)} seconds)`);
|
|
813
|
+
}
|
|
814
|
+
if (options.output.ppt.includeImages === undefined ||
|
|
815
|
+
options.output.ppt.includeImages === true) {
|
|
816
|
+
suggestions.push("Image generation is enabled. Each slide with images will take additional time (~2-5 seconds per image).");
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
errors.push(toValidationError(ErrorFactory.missingPPTProperty("output.ppt", [
|
|
821
|
+
"Provide PPT generation options under output.ppt",
|
|
822
|
+
"Specify number of slides, theme, and other preferences",
|
|
823
|
+
])));
|
|
824
|
+
}
|
|
825
|
+
// Add helpful suggestions
|
|
826
|
+
if (errors.length === 0 && warnings.length === 0) {
|
|
827
|
+
suggestions.push("PPT generation typically takes 30-120 seconds depending on slide count and image generation.");
|
|
828
|
+
}
|
|
829
|
+
return { isValid: errors.length === 0, errors, warnings, suggestions };
|
|
830
|
+
}
|
|
831
|
+
// ============================================================================
|
|
606
832
|
// HELPER FUNCTIONS
|
|
607
833
|
// ============================================================================
|
|
608
834
|
/**
|