@juspay/neurolink 9.30.0 → 9.31.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.
Files changed (977) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +2 -3
  3. package/dist/adapters/providerImageAdapter.js +13 -22
  4. package/dist/adapters/video/videoAnalyzer.d.ts +4 -4
  5. package/dist/adapters/video/videoAnalyzer.js +3 -3
  6. package/dist/agent/directTools.d.ts +20 -289
  7. package/dist/agent/directTools.js +11 -10
  8. package/dist/auth/accountPool.d.ts +68 -0
  9. package/dist/auth/accountPool.js +178 -0
  10. package/dist/auth/anthropicOAuth.d.ts +15 -5
  11. package/dist/auth/anthropicOAuth.js +117 -57
  12. package/dist/auth/index.d.ts +7 -5
  13. package/dist/auth/index.js +6 -2
  14. package/dist/auth/tokenStore.d.ts +71 -27
  15. package/dist/auth/tokenStore.js +342 -64
  16. package/dist/cli/commands/auth.d.ts +39 -2
  17. package/dist/cli/commands/auth.js +585 -36
  18. package/dist/cli/commands/config.d.ts +47 -574
  19. package/dist/cli/commands/config.js +142 -24
  20. package/dist/cli/commands/docs.d.ts +1 -5
  21. package/dist/cli/commands/observability.d.ts +1 -17
  22. package/dist/cli/commands/ollama.js +1 -1
  23. package/dist/cli/commands/proxy.d.ts +20 -0
  24. package/dist/cli/commands/proxy.js +1254 -0
  25. package/dist/cli/commands/setup-anthropic.js +1 -1
  26. package/dist/cli/commands/setup-azure.js +1 -1
  27. package/dist/cli/commands/setup-bedrock.js +2 -2
  28. package/dist/cli/commands/setup-gcp.js +1 -1
  29. package/dist/cli/commands/setup-google-ai.js +1 -1
  30. package/dist/cli/commands/setup-huggingface.js +2 -2
  31. package/dist/cli/commands/setup-mistral.js +1 -1
  32. package/dist/cli/commands/setup-openai.js +1 -1
  33. package/dist/cli/commands/setup.js +3 -3
  34. package/dist/cli/commands/telemetry.d.ts +1 -22
  35. package/dist/cli/factories/authCommandFactory.d.ts +16 -11
  36. package/dist/cli/factories/authCommandFactory.js +96 -1
  37. package/dist/cli/factories/ollamaCommandFactory.js +1 -1
  38. package/dist/cli/factories/sagemakerCommandFactory.js +25 -6
  39. package/dist/cli/index.d.ts +0 -6
  40. package/dist/cli/index.js +5 -2
  41. package/dist/cli/loop/conversationSelector.js +7 -2
  42. package/dist/cli/parser.js +19 -1
  43. package/dist/cli/utils/envManager.js +2 -2
  44. package/dist/cli/utils/ollamaUtils.d.ts +1 -2
  45. package/dist/client/adapters/providerImageAdapter.js +588 -0
  46. package/dist/client/adapters/tts/googleTTSHandler.js +344 -0
  47. package/dist/client/adapters/video/directorPipeline.js +516 -0
  48. package/dist/client/adapters/video/ffmpegAdapter.js +206 -0
  49. package/dist/client/adapters/video/frameExtractor.js +143 -0
  50. package/dist/client/adapters/video/vertexVideoHandler.js +763 -0
  51. package/dist/client/adapters/video/videoAnalyzer.js +238 -0
  52. package/dist/client/adapters/video/videoMerger.js +171 -0
  53. package/dist/client/agent/directTools.js +840 -0
  54. package/dist/client/aiSdkAdapter.d.ts +196 -0
  55. package/dist/client/aiSdkAdapter.js +487 -0
  56. package/dist/client/auth/anthropicOAuth.js +974 -0
  57. package/dist/client/auth/tokenStore.js +799 -0
  58. package/dist/client/auth.d.ts +248 -0
  59. package/dist/client/auth.js +473 -0
  60. package/dist/client/client/aiSdkAdapter.js +487 -0
  61. package/dist/client/client/auth.js +473 -0
  62. package/dist/client/client/errors.js +552 -0
  63. package/dist/client/client/httpClient.js +837 -0
  64. package/dist/client/client/index.js +172 -0
  65. package/dist/client/client/interceptors.js +601 -0
  66. package/dist/client/client/reactHooks.js +1159 -0
  67. package/dist/client/client/sseClient.js +545 -0
  68. package/dist/client/client/streamingClient.js +917 -0
  69. package/dist/client/client/wsClient.js +369 -0
  70. package/dist/client/config/configManager.js +303 -0
  71. package/dist/client/config/conversationMemory.js +86 -0
  72. package/dist/client/config/taskClassificationConfig.js +148 -0
  73. package/dist/client/constants/contextWindows.js +295 -0
  74. package/dist/client/constants/enums.js +853 -0
  75. package/dist/client/constants/index.js +207 -0
  76. package/dist/client/constants/performance.js +389 -0
  77. package/dist/client/constants/retry.js +266 -0
  78. package/dist/client/constants/timeouts.js +182 -0
  79. package/dist/client/constants/tokens.js +380 -0
  80. package/dist/client/constants/videoErrors.js +46 -0
  81. package/dist/client/context/budgetChecker.js +98 -0
  82. package/dist/client/context/contextCompactor.js +205 -0
  83. package/dist/client/context/emergencyTruncation.js +88 -0
  84. package/dist/client/context/errorDetection.js +171 -0
  85. package/dist/client/context/errors.js +21 -0
  86. package/dist/client/context/fileTokenBudget.js +127 -0
  87. package/dist/client/context/prompts/summarizationPrompt.js +117 -0
  88. package/dist/client/context/stages/fileReadDeduplicator.js +66 -0
  89. package/dist/client/context/stages/slidingWindowTruncator.js +190 -0
  90. package/dist/client/context/stages/structuredSummarizer.js +99 -0
  91. package/dist/client/context/stages/toolOutputPruner.js +52 -0
  92. package/dist/client/context/summarizationEngine.js +136 -0
  93. package/dist/client/context/toolOutputLimits.js +78 -0
  94. package/dist/client/context/toolPairRepair.js +66 -0
  95. package/dist/client/core/analytics.js +88 -0
  96. package/dist/client/core/baseProvider.js +1385 -0
  97. package/dist/client/core/constants.js +140 -0
  98. package/dist/client/core/conversationMemoryFactory.js +141 -0
  99. package/dist/client/core/conversationMemoryInitializer.js +128 -0
  100. package/dist/client/core/conversationMemoryManager.js +344 -0
  101. package/dist/client/core/dynamicModels.js +358 -0
  102. package/dist/client/core/evaluation.js +309 -0
  103. package/dist/client/core/evaluationProviders.js +248 -0
  104. package/dist/client/core/factory.js +412 -0
  105. package/dist/client/core/infrastructure/baseError.js +22 -0
  106. package/dist/client/core/infrastructure/baseFactory.js +54 -0
  107. package/dist/client/core/infrastructure/baseRegistry.js +49 -0
  108. package/dist/client/core/infrastructure/index.js +5 -0
  109. package/dist/client/core/infrastructure/retry.js +20 -0
  110. package/dist/client/core/infrastructure/typedEventEmitter.js +23 -0
  111. package/dist/client/core/modelConfiguration.js +851 -0
  112. package/dist/client/core/modules/GenerationHandler.js +588 -0
  113. package/dist/client/core/modules/MessageBuilder.js +273 -0
  114. package/dist/client/core/modules/StreamHandler.js +185 -0
  115. package/dist/client/core/modules/TelemetryHandler.js +203 -0
  116. package/dist/client/core/modules/ToolsManager.js +499 -0
  117. package/dist/client/core/modules/Utilities.js +331 -0
  118. package/dist/client/core/redisConversationMemoryManager.js +1435 -0
  119. package/dist/client/core/streamAnalytics.js +131 -0
  120. package/dist/client/errors.d.ts +299 -0
  121. package/dist/client/errors.js +552 -0
  122. package/dist/client/evaluation/contextBuilder.js +134 -0
  123. package/dist/client/evaluation/index.js +61 -0
  124. package/dist/client/evaluation/prompts.js +73 -0
  125. package/dist/client/evaluation/ragasEvaluator.js +110 -0
  126. package/dist/client/evaluation/retryManager.js +78 -0
  127. package/dist/client/evaluation/scoring.js +61 -0
  128. package/dist/client/factories/providerFactory.js +166 -0
  129. package/dist/client/factories/providerRegistry.js +166 -0
  130. package/dist/client/features/ppt/constants.js +896 -0
  131. package/dist/client/features/ppt/contentPlanner.js +529 -0
  132. package/dist/client/features/ppt/presentationOrchestrator.js +236 -0
  133. package/dist/client/features/ppt/slideGenerator.js +532 -0
  134. package/dist/client/features/ppt/slideRenderers.js +2383 -0
  135. package/dist/client/features/ppt/slideTypeInference.js +405 -0
  136. package/dist/client/features/ppt/types.js +13 -0
  137. package/dist/client/features/ppt/utils.js +443 -0
  138. package/dist/client/files/fileReferenceRegistry.js +1543 -0
  139. package/dist/client/files/fileTools.js +450 -0
  140. package/dist/client/files/streamingReader.js +321 -0
  141. package/dist/client/files/types.js +23 -0
  142. package/dist/client/hitl/hitlErrors.js +54 -0
  143. package/dist/client/hitl/hitlManager.js +460 -0
  144. package/dist/client/httpClient.d.ts +297 -0
  145. package/dist/client/httpClient.js +837 -0
  146. package/dist/client/index.d.ts +111 -0
  147. package/dist/client/index.js +511 -0
  148. package/dist/client/interceptors.d.ts +283 -0
  149. package/dist/client/interceptors.js +601 -0
  150. package/dist/client/mcp/agentExposure.js +356 -0
  151. package/dist/client/mcp/auth/index.js +11 -0
  152. package/dist/client/mcp/auth/oauthClientProvider.js +325 -0
  153. package/dist/client/mcp/auth/tokenStorage.js +134 -0
  154. package/dist/client/mcp/batching/index.js +10 -0
  155. package/dist/client/mcp/batching/requestBatcher.js +441 -0
  156. package/dist/client/mcp/caching/index.js +10 -0
  157. package/dist/client/mcp/caching/toolCache.js +433 -0
  158. package/dist/client/mcp/elicitation/elicitationManager.js +376 -0
  159. package/dist/client/mcp/elicitation/index.js +11 -0
  160. package/dist/client/mcp/elicitation/types.js +10 -0
  161. package/dist/client/mcp/elicitationProtocol.js +375 -0
  162. package/dist/client/mcp/enhancedToolDiscovery.js +481 -0
  163. package/dist/client/mcp/externalServerManager.js +1478 -0
  164. package/dist/client/mcp/factory.js +161 -0
  165. package/dist/client/mcp/flexibleToolValidator.js +161 -0
  166. package/dist/client/mcp/httpRateLimiter.js +391 -0
  167. package/dist/client/mcp/httpRetryHandler.js +178 -0
  168. package/dist/client/mcp/index.js +74 -0
  169. package/dist/client/mcp/mcpCircuitBreaker.js +427 -0
  170. package/dist/client/mcp/mcpClientFactory.js +708 -0
  171. package/dist/client/mcp/mcpRegistryClient.js +488 -0
  172. package/dist/client/mcp/mcpServerBase.js +373 -0
  173. package/dist/client/mcp/multiServerManager.js +579 -0
  174. package/dist/client/mcp/registry.js +158 -0
  175. package/dist/client/mcp/routing/index.js +10 -0
  176. package/dist/client/mcp/routing/toolRouter.js +416 -0
  177. package/dist/client/mcp/serverCapabilities.js +502 -0
  178. package/dist/client/mcp/servers/agent/directToolsServer.js +150 -0
  179. package/dist/client/mcp/toolAnnotations.js +239 -0
  180. package/dist/client/mcp/toolConverter.js +258 -0
  181. package/dist/client/mcp/toolDiscoveryService.js +798 -0
  182. package/dist/client/mcp/toolIntegration.js +334 -0
  183. package/dist/client/mcp/toolRegistry.js +719 -0
  184. package/dist/client/memory/hippocampusInitializer.js +19 -0
  185. package/dist/client/memory/memoryRetrievalTools.js +166 -0
  186. package/dist/client/middleware/builtin/analytics.js +132 -0
  187. package/dist/client/middleware/builtin/autoEvaluation.js +203 -0
  188. package/dist/client/middleware/builtin/guardrails.js +109 -0
  189. package/dist/client/middleware/builtin/lifecycle.js +168 -0
  190. package/dist/client/middleware/factory.js +327 -0
  191. package/dist/client/middleware/registry.js +295 -0
  192. package/dist/client/middleware/utils/guardrailsUtils.js +396 -0
  193. package/dist/client/models/anthropicModels.js +527 -0
  194. package/dist/client/neurolink.js +8015 -0
  195. package/dist/client/observability/exporterRegistry.js +413 -0
  196. package/dist/client/observability/exporters/arizeExporter.js +138 -0
  197. package/dist/client/observability/exporters/baseExporter.js +190 -0
  198. package/dist/client/observability/exporters/braintrustExporter.js +154 -0
  199. package/dist/client/observability/exporters/datadogExporter.js +196 -0
  200. package/dist/client/observability/exporters/laminarExporter.js +302 -0
  201. package/dist/client/observability/exporters/langfuseExporter.js +209 -0
  202. package/dist/client/observability/exporters/langsmithExporter.js +143 -0
  203. package/dist/client/observability/exporters/otelExporter.js +164 -0
  204. package/dist/client/observability/exporters/posthogExporter.js +287 -0
  205. package/dist/client/observability/exporters/sentryExporter.js +165 -0
  206. package/dist/client/observability/index.js +31 -0
  207. package/dist/client/observability/metricsAggregator.js +556 -0
  208. package/dist/client/observability/otelBridge.js +131 -0
  209. package/dist/client/observability/retryPolicy.js +383 -0
  210. package/dist/client/observability/sampling/samplers.js +216 -0
  211. package/dist/client/observability/spanProcessor.js +303 -0
  212. package/dist/client/observability/tokenTracker.js +413 -0
  213. package/dist/client/observability/types/exporterTypes.js +5 -0
  214. package/dist/client/observability/types/index.js +4 -0
  215. package/dist/client/observability/types/spanTypes.js +92 -0
  216. package/dist/client/observability/utils/safeMetadata.js +25 -0
  217. package/dist/client/observability/utils/spanSerializer.js +292 -0
  218. package/dist/client/processors/archive/ArchiveProcessor.js +1308 -0
  219. package/dist/client/processors/base/BaseFileProcessor.js +614 -0
  220. package/dist/client/processors/base/types.js +82 -0
  221. package/dist/client/processors/config/fileTypes.js +520 -0
  222. package/dist/client/processors/config/index.js +92 -0
  223. package/dist/client/processors/config/languageMap.js +410 -0
  224. package/dist/client/processors/config/mimeTypes.js +363 -0
  225. package/dist/client/processors/config/sizeLimits.js +258 -0
  226. package/dist/client/processors/document/ExcelProcessor.js +590 -0
  227. package/dist/client/processors/document/OpenDocumentProcessor.js +212 -0
  228. package/dist/client/processors/document/PptxProcessor.js +157 -0
  229. package/dist/client/processors/document/RtfProcessor.js +361 -0
  230. package/dist/client/processors/document/WordProcessor.js +353 -0
  231. package/dist/client/processors/errors/FileErrorCode.js +255 -0
  232. package/dist/client/processors/errors/errorHelpers.js +386 -0
  233. package/dist/client/processors/errors/errorSerializer.js +507 -0
  234. package/dist/client/processors/errors/index.js +49 -0
  235. package/dist/client/processors/markup/SvgProcessor.js +240 -0
  236. package/dist/client/processors/media/AudioProcessor.js +707 -0
  237. package/dist/client/processors/media/VideoProcessor.js +1045 -0
  238. package/dist/client/providers/amazonBedrock.js +1512 -0
  239. package/dist/client/providers/amazonSagemaker.js +162 -0
  240. package/dist/client/providers/anthropic.js +831 -0
  241. package/dist/client/providers/azureOpenai.js +143 -0
  242. package/dist/client/providers/googleAiStudio.js +1200 -0
  243. package/dist/client/providers/googleNativeGemini3.js +543 -0
  244. package/dist/client/providers/googleVertex.js +2936 -0
  245. package/dist/client/providers/huggingFace.js +315 -0
  246. package/dist/client/providers/litellm.js +488 -0
  247. package/dist/client/providers/mistral.js +157 -0
  248. package/dist/client/providers/ollama.js +1579 -0
  249. package/dist/client/providers/openAI.js +627 -0
  250. package/dist/client/providers/openRouter.js +543 -0
  251. package/dist/client/providers/openaiCompatible.js +290 -0
  252. package/dist/client/providers/providerTypeUtils.js +46 -0
  253. package/dist/client/providers/sagemaker/adaptive-semaphore.js +215 -0
  254. package/dist/client/providers/sagemaker/client.js +472 -0
  255. package/dist/client/providers/sagemaker/config.js +317 -0
  256. package/dist/client/providers/sagemaker/detection.js +606 -0
  257. package/dist/client/providers/sagemaker/error-constants.js +227 -0
  258. package/dist/client/providers/sagemaker/errors.js +299 -0
  259. package/dist/client/providers/sagemaker/language-model.js +775 -0
  260. package/dist/client/providers/sagemaker/parsers.js +634 -0
  261. package/dist/client/providers/sagemaker/streaming.js +331 -0
  262. package/dist/client/providers/sagemaker/structured-parser.js +625 -0
  263. package/dist/client/proxy/accountQuota.js +162 -0
  264. package/dist/client/proxy/claudeFormat.js +595 -0
  265. package/dist/client/proxy/modelRouter.js +29 -0
  266. package/dist/client/proxy/oauthFetch.js +367 -0
  267. package/dist/client/proxy/proxyFetch.js +586 -0
  268. package/dist/client/proxy/requestLogger.js +207 -0
  269. package/dist/client/proxy/tokenRefresh.js +124 -0
  270. package/dist/client/proxy/usageStats.js +74 -0
  271. package/dist/client/proxy/utils/noProxyUtils.js +149 -0
  272. package/dist/client/rag/ChunkerFactory.js +320 -0
  273. package/dist/client/rag/ChunkerRegistry.js +421 -0
  274. package/dist/client/rag/chunkers/BaseChunker.js +143 -0
  275. package/dist/client/rag/chunkers/CharacterChunker.js +28 -0
  276. package/dist/client/rag/chunkers/HTMLChunker.js +38 -0
  277. package/dist/client/rag/chunkers/JSONChunker.js +68 -0
  278. package/dist/client/rag/chunkers/LaTeXChunker.js +63 -0
  279. package/dist/client/rag/chunkers/MarkdownChunker.js +306 -0
  280. package/dist/client/rag/chunkers/RecursiveChunker.js +139 -0
  281. package/dist/client/rag/chunkers/SemanticMarkdownChunker.js +138 -0
  282. package/dist/client/rag/chunkers/SentenceChunker.js +66 -0
  283. package/dist/client/rag/chunkers/TokenChunker.js +61 -0
  284. package/dist/client/rag/chunkers/index.js +15 -0
  285. package/dist/client/rag/chunking/characterChunker.js +142 -0
  286. package/dist/client/rag/chunking/chunkerRegistry.js +194 -0
  287. package/dist/client/rag/chunking/htmlChunker.js +247 -0
  288. package/dist/client/rag/chunking/index.js +17 -0
  289. package/dist/client/rag/chunking/jsonChunker.js +281 -0
  290. package/dist/client/rag/chunking/latexChunker.js +251 -0
  291. package/dist/client/rag/chunking/markdownChunker.js +373 -0
  292. package/dist/client/rag/chunking/recursiveChunker.js +148 -0
  293. package/dist/client/rag/chunking/semanticChunker.js +306 -0
  294. package/dist/client/rag/chunking/sentenceChunker.js +230 -0
  295. package/dist/client/rag/chunking/tokenChunker.js +183 -0
  296. package/dist/client/rag/document/MDocument.js +392 -0
  297. package/dist/client/rag/document/index.js +5 -0
  298. package/dist/client/rag/document/loaders.js +500 -0
  299. package/dist/client/rag/errors/RAGError.js +274 -0
  300. package/dist/client/rag/errors/index.js +6 -0
  301. package/dist/client/rag/graphRag/graphRAG.js +401 -0
  302. package/dist/client/rag/graphRag/index.js +4 -0
  303. package/dist/client/rag/index.js +141 -0
  304. package/dist/client/rag/metadata/MetadataExtractorFactory.js +418 -0
  305. package/dist/client/rag/metadata/MetadataExtractorRegistry.js +362 -0
  306. package/dist/client/rag/metadata/index.js +9 -0
  307. package/dist/client/rag/metadata/metadataExtractor.js +280 -0
  308. package/dist/client/rag/pipeline/RAGPipeline.js +436 -0
  309. package/dist/client/rag/pipeline/contextAssembly.js +341 -0
  310. package/dist/client/rag/pipeline/index.js +5 -0
  311. package/dist/client/rag/ragIntegration.js +321 -0
  312. package/dist/client/rag/reranker/RerankerFactory.js +430 -0
  313. package/dist/client/rag/reranker/RerankerRegistry.js +402 -0
  314. package/dist/client/rag/reranker/index.js +9 -0
  315. package/dist/client/rag/reranker/reranker.js +277 -0
  316. package/dist/client/rag/resilience/CircuitBreaker.js +431 -0
  317. package/dist/client/rag/resilience/RetryHandler.js +304 -0
  318. package/dist/client/rag/resilience/index.js +7 -0
  319. package/dist/client/rag/retrieval/hybridSearch.js +335 -0
  320. package/dist/client/rag/retrieval/index.js +5 -0
  321. package/dist/client/rag/retrieval/vectorQueryTool.js +307 -0
  322. package/dist/client/rag/types.js +8 -0
  323. package/dist/client/reactHooks.d.ts +239 -0
  324. package/dist/client/reactHooks.tsx +1483 -0
  325. package/dist/client/sdk/toolRegistration.js +377 -0
  326. package/dist/client/server/abstract/baseServerAdapter.js +575 -0
  327. package/dist/client/server/adapters/expressAdapter.js +486 -0
  328. package/dist/client/server/adapters/fastifyAdapter.js +472 -0
  329. package/dist/client/server/adapters/honoAdapter.js +632 -0
  330. package/dist/client/server/adapters/koaAdapter.js +510 -0
  331. package/dist/client/server/errors.js +486 -0
  332. package/dist/client/server/factory/serverAdapterFactory.js +160 -0
  333. package/dist/client/server/index.js +108 -0
  334. package/dist/client/server/middleware/abortSignal.js +111 -0
  335. package/dist/client/server/middleware/auth.js +388 -0
  336. package/dist/client/server/middleware/cache.js +359 -0
  337. package/dist/client/server/middleware/common.js +281 -0
  338. package/dist/client/server/middleware/deprecation.js +190 -0
  339. package/dist/client/server/middleware/mcpBodyAttachment.js +63 -0
  340. package/dist/client/server/middleware/rateLimit.js +227 -0
  341. package/dist/client/server/middleware/validation.js +388 -0
  342. package/dist/client/server/openapi/generator.js +398 -0
  343. package/dist/client/server/openapi/index.js +36 -0
  344. package/dist/client/server/openapi/schemas.js +695 -0
  345. package/dist/client/server/openapi/templates.js +374 -0
  346. package/dist/client/server/routes/agentRoutes.js +171 -0
  347. package/dist/client/server/routes/claudeProxyRoutes.js +1600 -0
  348. package/dist/client/server/routes/healthRoutes.js +187 -0
  349. package/dist/client/server/routes/index.js +57 -0
  350. package/dist/client/server/routes/mcpRoutes.js +342 -0
  351. package/dist/client/server/routes/memoryRoutes.js +350 -0
  352. package/dist/client/server/routes/openApiRoutes.js +126 -0
  353. package/dist/client/server/routes/toolRoutes.js +199 -0
  354. package/dist/client/server/streaming/dataStream.js +486 -0
  355. package/dist/client/server/streaming/index.js +11 -0
  356. package/dist/client/server/types.js +67 -0
  357. package/dist/client/server/utils/redaction.js +334 -0
  358. package/dist/client/server/utils/validation.js +243 -0
  359. package/dist/client/server/websocket/WebSocketHandler.js +383 -0
  360. package/dist/client/server/websocket/index.js +4 -0
  361. package/dist/client/services/server/ai/observability/instrumentation.js +808 -0
  362. package/dist/client/sseClient.d.ts +156 -0
  363. package/dist/client/sseClient.js +545 -0
  364. package/dist/client/streamingClient.d.ts +327 -0
  365. package/dist/client/streamingClient.js +917 -0
  366. package/dist/client/telemetry/attributes.js +100 -0
  367. package/dist/client/telemetry/index.js +26 -0
  368. package/dist/client/telemetry/telemetryService.js +308 -0
  369. package/dist/client/telemetry/tracers.js +17 -0
  370. package/dist/client/telemetry/withSpan.js +34 -0
  371. package/dist/client/types/actionTypes.js +6 -0
  372. package/dist/client/types/analytics.js +5 -0
  373. package/dist/client/types/authTypes.js +8 -0
  374. package/dist/client/types/circuitBreakerErrors.js +34 -0
  375. package/dist/client/types/cli.js +21 -0
  376. package/dist/client/types/clientTypes.js +10 -0
  377. package/dist/client/types/common.js +51 -0
  378. package/dist/client/types/configTypes.js +49 -0
  379. package/dist/client/types/content.js +19 -0
  380. package/dist/client/types/contextTypes.js +400 -0
  381. package/dist/client/types/conversation.js +47 -0
  382. package/dist/client/types/conversationMemoryInterface.js +6 -0
  383. package/dist/client/types/domainTypes.js +5 -0
  384. package/dist/client/types/errors.js +167 -0
  385. package/dist/client/types/evaluation.js +5 -0
  386. package/dist/client/types/evaluationProviders.js +5 -0
  387. package/dist/client/types/evaluationTypes.js +1 -0
  388. package/dist/client/types/externalMcp.js +6 -0
  389. package/dist/client/types/fileReferenceTypes.js +8 -0
  390. package/dist/client/types/fileTypes.js +4 -0
  391. package/dist/client/types/generateTypes.js +1 -0
  392. package/dist/client/types/guardrails.js +1 -0
  393. package/dist/client/types/hitlTypes.js +8 -0
  394. package/dist/client/types/index.js +57 -0
  395. package/dist/client/types/mcpTypes.js +5 -0
  396. package/dist/client/types/middlewareTypes.js +1 -0
  397. package/dist/client/types/modelTypes.js +30 -0
  398. package/dist/client/types/multimodal.js +135 -0
  399. package/dist/client/types/observability.js +6 -0
  400. package/dist/client/types/pptTypes.js +82 -0
  401. package/dist/client/types/providers.js +111 -0
  402. package/dist/client/types/proxyTypes.js +16 -0
  403. package/dist/client/types/ragTypes.js +7 -0
  404. package/dist/client/types/sdkTypes.js +8 -0
  405. package/dist/client/types/serviceTypes.js +5 -0
  406. package/dist/client/types/streamTypes.js +1 -0
  407. package/dist/client/types/subscriptionTypes.js +9 -0
  408. package/dist/client/types/taskClassificationTypes.js +5 -0
  409. package/dist/client/types/tools.js +24 -0
  410. package/dist/client/types/ttsTypes.js +57 -0
  411. package/dist/client/types/typeAliases.js +48 -0
  412. package/dist/client/types/utilities.js +4 -0
  413. package/dist/client/types/workflowTypes.js +30 -0
  414. package/dist/client/utils/async/withTimeout.js +98 -0
  415. package/dist/client/utils/asyncMutex.js +60 -0
  416. package/dist/client/utils/conversationMemory.js +431 -0
  417. package/dist/client/utils/csvProcessor.js +846 -0
  418. package/dist/client/utils/errorHandling.js +936 -0
  419. package/dist/client/utils/evaluationUtils.js +131 -0
  420. package/dist/client/utils/factoryProcessing.js +589 -0
  421. package/dist/client/utils/fileDetector.js +2161 -0
  422. package/dist/client/utils/imageCache.js +376 -0
  423. package/dist/client/utils/imageProcessor.js +704 -0
  424. package/dist/client/utils/logger.js +491 -0
  425. package/dist/client/utils/mcpDefaults.js +134 -0
  426. package/dist/client/utils/messageBuilder.js +1653 -0
  427. package/dist/client/utils/modelAliasResolver.js +54 -0
  428. package/dist/client/utils/modelDetection.js +80 -0
  429. package/dist/client/utils/modelRouter.js +292 -0
  430. package/dist/client/utils/multimodalOptionsBuilder.js +65 -0
  431. package/dist/client/utils/observabilityHelpers.js +47 -0
  432. package/dist/client/utils/parameterValidation.js +966 -0
  433. package/dist/client/utils/pdfProcessor.js +410 -0
  434. package/dist/client/utils/performance.js +222 -0
  435. package/dist/client/utils/pricing.js +340 -0
  436. package/dist/client/utils/promptRedaction.js +62 -0
  437. package/dist/client/utils/providerConfig.js +1009 -0
  438. package/dist/client/utils/providerHealth.js +1237 -0
  439. package/dist/client/utils/providerRetry.js +112 -0
  440. package/dist/client/utils/providerUtils.js +434 -0
  441. package/dist/client/utils/rateLimiter.js +200 -0
  442. package/dist/client/utils/redis.js +368 -0
  443. package/dist/client/utils/retryHandler.js +269 -0
  444. package/dist/client/utils/retryability.js +22 -0
  445. package/dist/client/utils/sanitizers/svg.js +481 -0
  446. package/dist/client/utils/schemaConversion.js +255 -0
  447. package/dist/client/utils/taskClassificationUtils.js +149 -0
  448. package/dist/client/utils/taskClassifier.js +94 -0
  449. package/dist/client/utils/thinkingConfig.js +104 -0
  450. package/dist/client/utils/timeout.js +359 -0
  451. package/dist/client/utils/tokenEstimation.js +142 -0
  452. package/dist/client/utils/tokenLimits.js +125 -0
  453. package/dist/client/utils/tokenUtils.js +239 -0
  454. package/dist/client/utils/toolUtils.js +75 -0
  455. package/dist/client/utils/transformationUtils.js +554 -0
  456. package/dist/client/utils/ttsProcessor.js +286 -0
  457. package/dist/client/utils/typeUtils.js +97 -0
  458. package/dist/client/utils/videoAnalysisProcessor.js +67 -0
  459. package/dist/client/workflow/config.js +398 -0
  460. package/dist/client/workflow/core/ensembleExecutor.js +407 -0
  461. package/dist/client/workflow/core/judgeScorer.js +544 -0
  462. package/dist/client/workflow/core/responseConditioner.js +225 -0
  463. package/dist/client/workflow/core/types/conditionerTypes.js +7 -0
  464. package/dist/client/workflow/core/types/ensembleTypes.js +7 -0
  465. package/dist/client/workflow/core/types/index.js +7 -0
  466. package/dist/client/workflow/core/types/judgeTypes.js +7 -0
  467. package/dist/client/workflow/core/types/layerTypes.js +7 -0
  468. package/dist/client/workflow/core/types/registryTypes.js +7 -0
  469. package/dist/client/workflow/core/workflowRegistry.js +304 -0
  470. package/dist/client/workflow/core/workflowRunner.js +586 -0
  471. package/dist/client/workflow/index.js +50 -0
  472. package/dist/client/workflow/types.js +9 -0
  473. package/dist/client/workflow/utils/types/index.js +7 -0
  474. package/dist/client/workflow/utils/workflowMetrics.js +311 -0
  475. package/dist/client/workflow/utils/workflowValidation.js +420 -0
  476. package/dist/client/workflow/workflows/adaptiveWorkflow.js +366 -0
  477. package/dist/client/workflow/workflows/consensusWorkflow.js +192 -0
  478. package/dist/client/workflow/workflows/fallbackWorkflow.js +225 -0
  479. package/dist/client/workflow/workflows/multiJudgeWorkflow.js +351 -0
  480. package/dist/client/wsClient.d.ts +130 -0
  481. package/dist/client/wsClient.js +369 -0
  482. package/dist/config/configManager.js +2 -2
  483. package/dist/constants/contextWindows.js +15 -13
  484. package/dist/constants/enums.d.ts +10 -16
  485. package/dist/constants/enums.js +12 -18
  486. package/dist/constants/index.d.ts +0 -10
  487. package/dist/constants/index.js +1 -1
  488. package/dist/constants/tokens.d.ts +29 -16
  489. package/dist/constants/tokens.js +23 -16
  490. package/dist/core/baseProvider.d.ts +5 -5
  491. package/dist/core/baseProvider.js +6 -6
  492. package/dist/core/constants.js +6 -1
  493. package/dist/core/dynamicModels.js +10 -6
  494. package/dist/core/evaluationProviders.js +1 -1
  495. package/dist/core/infrastructure/baseError.d.ts +1 -1
  496. package/dist/core/infrastructure/baseFactory.d.ts +1 -6
  497. package/dist/core/infrastructure/baseRegistry.d.ts +6 -5
  498. package/dist/core/infrastructure/index.d.ts +6 -4
  499. package/dist/core/infrastructure/index.js +2 -2
  500. package/dist/core/modelConfiguration.js +3 -1
  501. package/dist/core/modules/GenerationHandler.d.ts +3 -3
  502. package/dist/core/modules/GenerationHandler.js +49 -41
  503. package/dist/core/modules/MessageBuilder.d.ts +5 -5
  504. package/dist/core/modules/MessageBuilder.js +4 -6
  505. package/dist/core/modules/StreamHandler.js +26 -12
  506. package/dist/core/modules/TelemetryHandler.d.ts +4 -6
  507. package/dist/core/modules/TelemetryHandler.js +7 -6
  508. package/dist/core/modules/ToolsManager.d.ts +2 -12
  509. package/dist/core/modules/ToolsManager.js +20 -4
  510. package/dist/core/modules/Utilities.js +3 -1
  511. package/dist/core/redisConversationMemoryManager.js +3 -3
  512. package/dist/core/streamAnalytics.js +23 -9
  513. package/dist/evaluation/contextBuilder.d.ts +2 -2
  514. package/dist/evaluation/contextBuilder.js +2 -2
  515. package/dist/evaluation/index.d.ts +2 -2
  516. package/dist/evaluation/retryManager.js +1 -1
  517. package/dist/factories/providerFactory.js +2 -2
  518. package/dist/features/ppt/constants.js +1 -1
  519. package/dist/features/ppt/presentationOrchestrator.js +7 -3
  520. package/dist/features/ppt/slideGenerator.d.ts +2 -1
  521. package/dist/features/ppt/slideGenerator.js +6 -1
  522. package/dist/files/fileTools.d.ts +16 -247
  523. package/dist/files/fileTools.js +16 -15
  524. package/dist/index.d.ts +5 -3
  525. package/dist/index.js +20 -3
  526. package/dist/lib/adapters/providerImageAdapter.js +13 -22
  527. package/dist/lib/adapters/video/videoAnalyzer.d.ts +4 -4
  528. package/dist/lib/adapters/video/videoAnalyzer.js +3 -3
  529. package/dist/lib/agent/directTools.d.ts +20 -289
  530. package/dist/lib/agent/directTools.js +11 -10
  531. package/dist/lib/auth/accountPool.d.ts +68 -0
  532. package/dist/lib/auth/accountPool.js +179 -0
  533. package/dist/lib/auth/anthropicOAuth.d.ts +15 -5
  534. package/dist/lib/auth/anthropicOAuth.js +117 -57
  535. package/dist/lib/auth/index.d.ts +7 -5
  536. package/dist/lib/auth/index.js +6 -2
  537. package/dist/lib/auth/tokenStore.d.ts +71 -27
  538. package/dist/lib/auth/tokenStore.js +342 -64
  539. package/dist/lib/client/aiSdkAdapter.d.ts +196 -0
  540. package/dist/lib/client/aiSdkAdapter.js +488 -0
  541. package/dist/lib/client/auth.d.ts +248 -0
  542. package/dist/lib/client/auth.js +474 -0
  543. package/dist/lib/client/errors.d.ts +299 -0
  544. package/dist/lib/client/errors.js +553 -0
  545. package/dist/lib/client/httpClient.d.ts +297 -0
  546. package/dist/lib/client/httpClient.js +838 -0
  547. package/dist/lib/client/index.d.ts +111 -0
  548. package/dist/lib/client/index.js +173 -0
  549. package/dist/lib/client/interceptors.d.ts +283 -0
  550. package/dist/lib/client/interceptors.js +602 -0
  551. package/dist/lib/client/reactHooks.d.ts +239 -0
  552. package/dist/lib/client/reactHooks.js +1160 -0
  553. package/dist/lib/client/sseClient.d.ts +156 -0
  554. package/dist/lib/client/sseClient.js +546 -0
  555. package/dist/lib/client/streamingClient.d.ts +327 -0
  556. package/dist/lib/client/streamingClient.js +918 -0
  557. package/dist/lib/client/wsClient.d.ts +130 -0
  558. package/dist/lib/client/wsClient.js +370 -0
  559. package/dist/lib/config/configManager.js +2 -2
  560. package/dist/lib/constants/contextWindows.js +15 -13
  561. package/dist/lib/constants/enums.d.ts +10 -16
  562. package/dist/lib/constants/enums.js +12 -18
  563. package/dist/lib/constants/index.d.ts +0 -10
  564. package/dist/lib/constants/index.js +1 -1
  565. package/dist/lib/constants/tokens.d.ts +29 -16
  566. package/dist/lib/constants/tokens.js +23 -16
  567. package/dist/lib/core/baseProvider.d.ts +5 -5
  568. package/dist/lib/core/baseProvider.js +6 -6
  569. package/dist/lib/core/constants.js +6 -1
  570. package/dist/lib/core/dynamicModels.js +10 -6
  571. package/dist/lib/core/evaluationProviders.js +1 -1
  572. package/dist/lib/core/infrastructure/baseError.d.ts +1 -1
  573. package/dist/lib/core/infrastructure/baseFactory.d.ts +1 -6
  574. package/dist/lib/core/infrastructure/baseRegistry.d.ts +6 -5
  575. package/dist/lib/core/infrastructure/index.d.ts +6 -4
  576. package/dist/lib/core/infrastructure/index.js +2 -2
  577. package/dist/lib/core/modelConfiguration.js +3 -1
  578. package/dist/lib/core/modules/GenerationHandler.d.ts +3 -3
  579. package/dist/lib/core/modules/GenerationHandler.js +49 -41
  580. package/dist/lib/core/modules/MessageBuilder.d.ts +5 -5
  581. package/dist/lib/core/modules/MessageBuilder.js +4 -6
  582. package/dist/lib/core/modules/StreamHandler.js +26 -12
  583. package/dist/lib/core/modules/TelemetryHandler.d.ts +4 -6
  584. package/dist/lib/core/modules/TelemetryHandler.js +7 -6
  585. package/dist/lib/core/modules/ToolsManager.d.ts +2 -12
  586. package/dist/lib/core/modules/ToolsManager.js +20 -4
  587. package/dist/lib/core/modules/Utilities.js +3 -1
  588. package/dist/lib/core/redisConversationMemoryManager.js +3 -3
  589. package/dist/lib/core/streamAnalytics.js +23 -9
  590. package/dist/lib/evaluation/contextBuilder.d.ts +2 -2
  591. package/dist/lib/evaluation/contextBuilder.js +2 -2
  592. package/dist/lib/evaluation/index.d.ts +2 -2
  593. package/dist/lib/evaluation/retryManager.js +1 -1
  594. package/dist/lib/factories/providerFactory.js +2 -2
  595. package/dist/lib/features/ppt/constants.js +1 -1
  596. package/dist/lib/features/ppt/presentationOrchestrator.js +7 -3
  597. package/dist/lib/features/ppt/slideGenerator.d.ts +2 -1
  598. package/dist/lib/features/ppt/slideGenerator.js +6 -1
  599. package/dist/lib/files/fileTools.d.ts +16 -247
  600. package/dist/lib/files/fileTools.js +16 -15
  601. package/dist/lib/index.d.ts +5 -3
  602. package/dist/lib/index.js +20 -3
  603. package/dist/lib/mcp/batching/requestBatcher.js +1 -1
  604. package/dist/lib/mcp/externalServerManager.js +5 -2
  605. package/dist/lib/mcp/factory.js +1 -1
  606. package/dist/lib/mcp/index.d.ts +1 -1
  607. package/dist/lib/mcp/index.js +1 -1
  608. package/dist/lib/mcp/mcpCircuitBreaker.d.ts +1 -0
  609. package/dist/lib/mcp/mcpCircuitBreaker.js +30 -4
  610. package/dist/lib/mcp/mcpClientFactory.js +33 -4
  611. package/dist/lib/mcp/toolDiscoveryService.js +52 -5
  612. package/dist/lib/mcp/toolRegistry.js +7 -1
  613. package/dist/lib/memory/memoryRetrievalTools.d.ts +5 -89
  614. package/dist/lib/memory/memoryRetrievalTools.js +1 -1
  615. package/dist/lib/middleware/builtin/analytics.js +3 -0
  616. package/dist/lib/middleware/builtin/autoEvaluation.js +46 -24
  617. package/dist/lib/middleware/builtin/guardrails.js +4 -0
  618. package/dist/lib/middleware/builtin/lifecycle.js +10 -6
  619. package/dist/lib/middleware/factory.d.ts +3 -3
  620. package/dist/lib/middleware/factory.js +3 -2
  621. package/dist/lib/middleware/index.d.ts +1 -1
  622. package/dist/lib/middleware/registry.d.ts +2 -2
  623. package/dist/lib/middleware/registry.js +1 -0
  624. package/dist/lib/middleware/utils/guardrailsUtils.d.ts +5 -6
  625. package/dist/lib/middleware/utils/guardrailsUtils.js +15 -6
  626. package/dist/lib/neurolink.d.ts +9 -20
  627. package/dist/lib/neurolink.js +278 -186
  628. package/dist/lib/observability/retryPolicy.d.ts +2 -13
  629. package/dist/lib/observability/sampling/samplers.d.ts +2 -11
  630. package/dist/lib/observability/spanProcessor.d.ts +2 -14
  631. package/dist/lib/processors/base/BaseFileProcessor.js +1 -1
  632. package/dist/lib/processors/document/OpenDocumentProcessor.js +5 -3
  633. package/dist/lib/processors/media/VideoProcessor.js +157 -101
  634. package/dist/lib/providers/amazonBedrock.js +12 -5
  635. package/dist/lib/providers/amazonSagemaker.d.ts +5 -5
  636. package/dist/lib/providers/amazonSagemaker.js +6 -2
  637. package/dist/lib/providers/anthropic.d.ts +3 -3
  638. package/dist/lib/providers/anthropic.js +23 -192
  639. package/dist/lib/providers/anthropicBaseProvider.d.ts +4 -4
  640. package/dist/lib/providers/anthropicBaseProvider.js +24 -13
  641. package/dist/lib/providers/azureOpenai.d.ts +2 -2
  642. package/dist/lib/providers/azureOpenai.js +6 -6
  643. package/dist/lib/providers/googleAiStudio.d.ts +2 -2
  644. package/dist/lib/providers/googleAiStudio.js +15 -7
  645. package/dist/lib/providers/googleNativeGemini3.d.ts +3 -54
  646. package/dist/lib/providers/googleNativeGemini3.js +14 -10
  647. package/dist/lib/providers/googleVertex.d.ts +6 -6
  648. package/dist/lib/providers/googleVertex.js +32 -26
  649. package/dist/lib/providers/huggingFace.d.ts +4 -4
  650. package/dist/lib/providers/huggingFace.js +15 -5
  651. package/dist/lib/providers/litellm.d.ts +4 -4
  652. package/dist/lib/providers/litellm.js +54 -42
  653. package/dist/lib/providers/mistral.d.ts +2 -2
  654. package/dist/lib/providers/mistral.js +5 -4
  655. package/dist/lib/providers/ollama.d.ts +7 -4
  656. package/dist/lib/providers/ollama.js +30 -8
  657. package/dist/lib/providers/openAI.d.ts +2 -2
  658. package/dist/lib/providers/openAI.js +46 -21
  659. package/dist/lib/providers/openRouter.d.ts +4 -4
  660. package/dist/lib/providers/openRouter.js +63 -35
  661. package/dist/lib/providers/openaiCompatible.d.ts +2 -2
  662. package/dist/lib/providers/openaiCompatible.js +18 -9
  663. package/dist/lib/providers/providerTypeUtils.d.ts +28 -0
  664. package/dist/lib/providers/providerTypeUtils.js +47 -0
  665. package/dist/lib/providers/sagemaker/config.js +5 -5
  666. package/dist/lib/providers/sagemaker/language-model.d.ts +23 -13
  667. package/dist/lib/providers/sagemaker/language-model.js +20 -8
  668. package/dist/lib/proxy/accountQuota.d.ts +33 -0
  669. package/dist/lib/proxy/accountQuota.js +163 -0
  670. package/dist/lib/proxy/claudeFormat.d.ts +143 -0
  671. package/dist/lib/proxy/claudeFormat.js +596 -0
  672. package/dist/lib/proxy/cloaking/index.d.ts +44 -0
  673. package/dist/lib/proxy/cloaking/index.js +87 -0
  674. package/dist/lib/proxy/cloaking/plugins/headerScrubber.d.ts +9 -0
  675. package/dist/lib/proxy/cloaking/plugins/headerScrubber.js +87 -0
  676. package/dist/lib/proxy/cloaking/plugins/sessionIdentity.d.ts +15 -0
  677. package/dist/lib/proxy/cloaking/plugins/sessionIdentity.js +66 -0
  678. package/dist/lib/proxy/cloaking/plugins/systemPromptInjector.d.ts +11 -0
  679. package/dist/lib/proxy/cloaking/plugins/systemPromptInjector.js +84 -0
  680. package/dist/lib/proxy/cloaking/plugins/tlsFingerprint.d.ts +14 -0
  681. package/dist/lib/proxy/cloaking/plugins/tlsFingerprint.js +39 -0
  682. package/dist/lib/proxy/cloaking/plugins/wordObfuscator.d.ts +9 -0
  683. package/dist/lib/proxy/cloaking/plugins/wordObfuscator.js +122 -0
  684. package/dist/lib/proxy/cloaking/types.d.ts +1 -0
  685. package/dist/lib/proxy/cloaking/types.js +2 -0
  686. package/dist/lib/proxy/modelRouter.d.ts +10 -0
  687. package/dist/lib/proxy/modelRouter.js +30 -0
  688. package/dist/lib/proxy/oauthFetch.d.ts +36 -0
  689. package/dist/lib/proxy/oauthFetch.js +368 -0
  690. package/dist/lib/proxy/proxyConfig.d.ts +42 -0
  691. package/dist/lib/proxy/proxyConfig.js +500 -0
  692. package/dist/lib/proxy/proxyFetch.js +2 -1
  693. package/dist/lib/proxy/requestLogger.d.ts +50 -0
  694. package/dist/lib/proxy/requestLogger.js +208 -0
  695. package/dist/lib/proxy/tokenRefresh.d.ts +4 -0
  696. package/dist/lib/proxy/tokenRefresh.js +125 -0
  697. package/dist/lib/proxy/usageStats.d.ts +13 -0
  698. package/dist/lib/proxy/usageStats.js +75 -0
  699. package/dist/lib/rag/document/loaders.js +1 -1
  700. package/dist/lib/rag/pipeline/contextAssembly.d.ts +4 -7
  701. package/dist/lib/rag/ragIntegration.d.ts +2 -14
  702. package/dist/lib/rag/ragIntegration.js +1 -1
  703. package/dist/lib/rag/resilience/CircuitBreaker.d.ts +5 -44
  704. package/dist/lib/rag/resilience/RetryHandler.js +1 -1
  705. package/dist/lib/rag/retrieval/vectorQueryTool.d.ts +1 -9
  706. package/dist/lib/rag/retrieval/vectorQueryTool.js +1 -1
  707. package/dist/lib/sdk/toolRegistration.js +12 -1
  708. package/dist/lib/server/abstract/baseServerAdapter.js +2 -2
  709. package/dist/lib/server/adapters/honoAdapter.d.ts +6 -0
  710. package/dist/lib/server/adapters/honoAdapter.js +76 -10
  711. package/dist/lib/server/middleware/cache.js +3 -0
  712. package/dist/lib/server/routes/claudeProxyRoutes.d.ts +44 -0
  713. package/dist/lib/server/routes/claudeProxyRoutes.js +1601 -0
  714. package/dist/lib/server/routes/healthRoutes.js +18 -1
  715. package/dist/lib/server/routes/index.d.ts +7 -0
  716. package/dist/lib/server/routes/index.js +8 -0
  717. package/dist/lib/server/streaming/dataStream.d.ts +1 -5
  718. package/dist/lib/server/streaming/dataStream.js +3 -0
  719. package/dist/lib/server/utils/validation.d.ts +24 -124
  720. package/dist/lib/server/utils/validation.js +2 -2
  721. package/dist/lib/services/server/ai/observability/instrumentation.js +4 -0
  722. package/dist/lib/telemetry/attributes.d.ts +38 -0
  723. package/dist/lib/telemetry/attributes.js +40 -0
  724. package/dist/lib/telemetry/tracers.d.ts +1 -0
  725. package/dist/lib/telemetry/tracers.js +1 -0
  726. package/dist/lib/types/authTypes.d.ts +56 -0
  727. package/dist/lib/types/authTypes.js +9 -0
  728. package/dist/lib/types/circuitBreakerErrors.d.ts +30 -0
  729. package/dist/lib/types/circuitBreakerErrors.js +35 -0
  730. package/dist/lib/types/cli.d.ts +258 -0
  731. package/dist/lib/types/clientTypes.d.ts +1050 -0
  732. package/dist/lib/types/clientTypes.js +11 -0
  733. package/dist/lib/types/common.d.ts +123 -0
  734. package/dist/lib/types/configTypes.d.ts +49 -0
  735. package/dist/lib/types/configTypes.js +4 -0
  736. package/dist/lib/types/conversation.d.ts +0 -5
  737. package/dist/lib/types/evaluationTypes.d.ts +2 -2
  738. package/dist/lib/types/fileTypes.d.ts +47 -0
  739. package/dist/lib/types/generateTypes.d.ts +7 -3
  740. package/dist/lib/types/guardrails.d.ts +2 -2
  741. package/dist/lib/types/index.d.ts +4 -1
  742. package/dist/lib/types/index.js +5 -0
  743. package/dist/lib/types/middlewareTypes.d.ts +3 -3
  744. package/dist/lib/types/modelTypes.d.ts +7 -97
  745. package/dist/lib/types/modelTypes.js +3 -3
  746. package/dist/lib/types/observability.d.ts +37 -0
  747. package/dist/lib/types/providers.d.ts +107 -0
  748. package/dist/lib/types/proxyTypes.d.ts +536 -0
  749. package/dist/lib/types/proxyTypes.js +17 -0
  750. package/dist/lib/types/ragTypes.d.ts +49 -1
  751. package/dist/lib/types/streamTypes.d.ts +37 -13
  752. package/dist/lib/types/subscriptionTypes.d.ts +77 -0
  753. package/dist/lib/types/subscriptionTypes.js +2 -0
  754. package/dist/lib/types/tools.d.ts +45 -1
  755. package/dist/lib/types/typeAliases.d.ts +8 -0
  756. package/dist/lib/types/typeAliases.js +1 -0
  757. package/dist/lib/utils/async/retry.d.ts +4 -33
  758. package/dist/lib/utils/asyncMutex.d.ts +14 -0
  759. package/dist/lib/utils/asyncMutex.js +61 -0
  760. package/dist/lib/utils/errorHandling.d.ts +2 -1
  761. package/dist/lib/utils/errorHandling.js +14 -6
  762. package/dist/lib/utils/fileDetector.d.ts +13 -1
  763. package/dist/lib/utils/fileDetector.js +114 -32
  764. package/dist/lib/utils/imageProcessor.js +7 -7
  765. package/dist/lib/utils/json/safeParse.d.ts +1 -8
  766. package/dist/lib/utils/mcpDefaults.d.ts +1 -1
  767. package/dist/lib/utils/mcpDefaults.js +11 -2
  768. package/dist/lib/utils/messageBuilder.d.ts +5 -5
  769. package/dist/lib/utils/messageBuilder.js +106 -80
  770. package/dist/lib/utils/modelChoices.d.ts +1 -8
  771. package/dist/lib/utils/pdfProcessor.d.ts +1 -25
  772. package/dist/lib/utils/pdfProcessor.js +5 -4
  773. package/dist/lib/utils/pricing.js +28 -5
  774. package/dist/lib/utils/providerHealth.d.ts +1 -1
  775. package/dist/lib/utils/rateLimiter.d.ts +1 -15
  776. package/dist/lib/utils/redis.d.ts +1 -1
  777. package/dist/lib/utils/redis.js +3 -3
  778. package/dist/lib/utils/sanitizers/filename.d.ts +2 -22
  779. package/dist/lib/utils/sanitizers/index.d.ts +4 -2
  780. package/dist/lib/utils/sanitizers/svg.d.ts +1 -11
  781. package/dist/lib/utils/schemaConversion.js +4 -1
  782. package/dist/lib/utils/thinkingConfig.d.ts +1 -33
  783. package/dist/lib/utils/tokenUtils.d.ts +1 -39
  784. package/dist/lib/utils/videoAnalysisProcessor.d.ts +5 -5
  785. package/dist/lib/utils/videoAnalysisProcessor.js +2 -2
  786. package/dist/lib/workflow/config.d.ts +89 -1257
  787. package/dist/lib/workflow/utils/workflowValidation.js +1 -1
  788. package/dist/mcp/batching/requestBatcher.js +1 -1
  789. package/dist/mcp/externalServerManager.js +5 -2
  790. package/dist/mcp/factory.js +1 -1
  791. package/dist/mcp/index.d.ts +1 -1
  792. package/dist/mcp/index.js +1 -1
  793. package/dist/mcp/mcpCircuitBreaker.d.ts +1 -0
  794. package/dist/mcp/mcpCircuitBreaker.js +30 -4
  795. package/dist/mcp/mcpClientFactory.js +33 -4
  796. package/dist/mcp/toolDiscoveryService.js +52 -5
  797. package/dist/mcp/toolRegistry.js +7 -1
  798. package/dist/memory/memoryRetrievalTools.d.ts +5 -89
  799. package/dist/memory/memoryRetrievalTools.js +1 -1
  800. package/dist/middleware/builtin/analytics.js +3 -0
  801. package/dist/middleware/builtin/autoEvaluation.js +46 -24
  802. package/dist/middleware/builtin/guardrails.js +4 -0
  803. package/dist/middleware/builtin/lifecycle.js +10 -6
  804. package/dist/middleware/factory.d.ts +3 -3
  805. package/dist/middleware/factory.js +3 -2
  806. package/dist/middleware/index.d.ts +1 -1
  807. package/dist/middleware/registry.d.ts +2 -2
  808. package/dist/middleware/registry.js +1 -0
  809. package/dist/middleware/utils/guardrailsUtils.d.ts +5 -6
  810. package/dist/middleware/utils/guardrailsUtils.js +15 -6
  811. package/dist/neurolink.d.ts +9 -20
  812. package/dist/neurolink.js +278 -186
  813. package/dist/observability/retryPolicy.d.ts +2 -13
  814. package/dist/observability/sampling/samplers.d.ts +2 -11
  815. package/dist/observability/spanProcessor.d.ts +2 -14
  816. package/dist/processors/base/BaseFileProcessor.js +1 -1
  817. package/dist/processors/document/OpenDocumentProcessor.js +5 -3
  818. package/dist/processors/media/VideoProcessor.js +157 -101
  819. package/dist/providers/amazonBedrock.js +12 -5
  820. package/dist/providers/amazonSagemaker.d.ts +5 -5
  821. package/dist/providers/amazonSagemaker.js +6 -2
  822. package/dist/providers/anthropic.d.ts +3 -3
  823. package/dist/providers/anthropic.js +23 -192
  824. package/dist/providers/anthropicBaseProvider.d.ts +4 -4
  825. package/dist/providers/anthropicBaseProvider.js +24 -13
  826. package/dist/providers/azureOpenai.d.ts +2 -2
  827. package/dist/providers/azureOpenai.js +6 -6
  828. package/dist/providers/googleAiStudio.d.ts +2 -2
  829. package/dist/providers/googleAiStudio.js +15 -7
  830. package/dist/providers/googleNativeGemini3.d.ts +3 -54
  831. package/dist/providers/googleNativeGemini3.js +14 -10
  832. package/dist/providers/googleVertex.d.ts +6 -6
  833. package/dist/providers/googleVertex.js +32 -26
  834. package/dist/providers/huggingFace.d.ts +4 -4
  835. package/dist/providers/huggingFace.js +15 -5
  836. package/dist/providers/litellm.d.ts +4 -4
  837. package/dist/providers/litellm.js +54 -42
  838. package/dist/providers/mistral.d.ts +2 -2
  839. package/dist/providers/mistral.js +5 -4
  840. package/dist/providers/ollama.d.ts +7 -4
  841. package/dist/providers/ollama.js +30 -8
  842. package/dist/providers/openAI.d.ts +2 -2
  843. package/dist/providers/openAI.js +46 -21
  844. package/dist/providers/openRouter.d.ts +4 -4
  845. package/dist/providers/openRouter.js +63 -35
  846. package/dist/providers/openaiCompatible.d.ts +2 -2
  847. package/dist/providers/openaiCompatible.js +18 -9
  848. package/dist/providers/providerTypeUtils.d.ts +28 -0
  849. package/dist/providers/providerTypeUtils.js +46 -0
  850. package/dist/providers/sagemaker/config.js +5 -5
  851. package/dist/providers/sagemaker/language-model.d.ts +23 -13
  852. package/dist/providers/sagemaker/language-model.js +20 -8
  853. package/dist/proxy/accountQuota.d.ts +33 -0
  854. package/dist/proxy/accountQuota.js +162 -0
  855. package/dist/proxy/claudeFormat.d.ts +143 -0
  856. package/dist/proxy/claudeFormat.js +595 -0
  857. package/dist/proxy/cloaking/index.d.ts +44 -0
  858. package/dist/proxy/cloaking/index.js +86 -0
  859. package/dist/proxy/cloaking/plugins/headerScrubber.d.ts +9 -0
  860. package/dist/proxy/cloaking/plugins/headerScrubber.js +86 -0
  861. package/dist/proxy/cloaking/plugins/sessionIdentity.d.ts +15 -0
  862. package/dist/proxy/cloaking/plugins/sessionIdentity.js +65 -0
  863. package/dist/proxy/cloaking/plugins/systemPromptInjector.d.ts +11 -0
  864. package/dist/proxy/cloaking/plugins/systemPromptInjector.js +83 -0
  865. package/dist/proxy/cloaking/plugins/tlsFingerprint.d.ts +14 -0
  866. package/dist/proxy/cloaking/plugins/tlsFingerprint.js +38 -0
  867. package/dist/proxy/cloaking/plugins/wordObfuscator.d.ts +9 -0
  868. package/dist/proxy/cloaking/plugins/wordObfuscator.js +121 -0
  869. package/dist/proxy/cloaking/types.d.ts +1 -0
  870. package/dist/proxy/cloaking/types.js +1 -0
  871. package/dist/proxy/modelRouter.d.ts +10 -0
  872. package/dist/proxy/modelRouter.js +29 -0
  873. package/dist/proxy/oauthFetch.d.ts +36 -0
  874. package/dist/proxy/oauthFetch.js +367 -0
  875. package/dist/proxy/proxyConfig.d.ts +42 -0
  876. package/dist/proxy/proxyConfig.js +499 -0
  877. package/dist/proxy/proxyFetch.js +2 -1
  878. package/dist/proxy/requestLogger.d.ts +50 -0
  879. package/dist/proxy/requestLogger.js +207 -0
  880. package/dist/proxy/tokenRefresh.d.ts +4 -0
  881. package/dist/proxy/tokenRefresh.js +124 -0
  882. package/dist/proxy/usageStats.d.ts +13 -0
  883. package/dist/proxy/usageStats.js +74 -0
  884. package/dist/rag/document/loaders.js +1 -1
  885. package/dist/rag/pipeline/contextAssembly.d.ts +4 -7
  886. package/dist/rag/ragIntegration.d.ts +2 -14
  887. package/dist/rag/ragIntegration.js +1 -1
  888. package/dist/rag/resilience/CircuitBreaker.d.ts +5 -44
  889. package/dist/rag/resilience/RetryHandler.js +1 -1
  890. package/dist/rag/retrieval/vectorQueryTool.d.ts +1 -9
  891. package/dist/rag/retrieval/vectorQueryTool.js +1 -1
  892. package/dist/sdk/toolRegistration.js +12 -1
  893. package/dist/server/abstract/baseServerAdapter.js +2 -2
  894. package/dist/server/adapters/honoAdapter.d.ts +6 -0
  895. package/dist/server/adapters/honoAdapter.js +76 -10
  896. package/dist/server/middleware/cache.js +3 -0
  897. package/dist/server/routes/claudeProxyRoutes.d.ts +44 -0
  898. package/dist/server/routes/claudeProxyRoutes.js +1600 -0
  899. package/dist/server/routes/healthRoutes.js +18 -1
  900. package/dist/server/routes/index.d.ts +7 -0
  901. package/dist/server/routes/index.js +8 -0
  902. package/dist/server/streaming/dataStream.d.ts +1 -5
  903. package/dist/server/streaming/dataStream.js +3 -0
  904. package/dist/server/utils/validation.d.ts +24 -124
  905. package/dist/server/utils/validation.js +2 -2
  906. package/dist/services/server/ai/observability/instrumentation.js +4 -0
  907. package/dist/telemetry/attributes.d.ts +38 -0
  908. package/dist/telemetry/attributes.js +40 -0
  909. package/dist/telemetry/tracers.d.ts +1 -0
  910. package/dist/telemetry/tracers.js +1 -0
  911. package/dist/types/authTypes.d.ts +56 -0
  912. package/dist/types/authTypes.js +8 -0
  913. package/dist/types/circuitBreakerErrors.d.ts +30 -0
  914. package/dist/types/circuitBreakerErrors.js +34 -0
  915. package/dist/types/cli.d.ts +258 -0
  916. package/dist/types/clientTypes.d.ts +1050 -0
  917. package/dist/types/clientTypes.js +10 -0
  918. package/dist/types/common.d.ts +123 -0
  919. package/dist/types/configTypes.d.ts +49 -0
  920. package/dist/types/configTypes.js +4 -0
  921. package/dist/types/conversation.d.ts +0 -5
  922. package/dist/types/evaluationTypes.d.ts +2 -2
  923. package/dist/types/fileTypes.d.ts +47 -0
  924. package/dist/types/generateTypes.d.ts +7 -3
  925. package/dist/types/guardrails.d.ts +2 -2
  926. package/dist/types/index.d.ts +4 -1
  927. package/dist/types/index.js +5 -0
  928. package/dist/types/middlewareTypes.d.ts +3 -3
  929. package/dist/types/modelTypes.d.ts +7 -97
  930. package/dist/types/modelTypes.js +3 -3
  931. package/dist/types/observability.d.ts +37 -0
  932. package/dist/types/providers.d.ts +107 -0
  933. package/dist/types/proxyTypes.d.ts +536 -0
  934. package/dist/types/proxyTypes.js +16 -0
  935. package/dist/types/ragTypes.d.ts +49 -1
  936. package/dist/types/streamTypes.d.ts +37 -13
  937. package/dist/types/subscriptionTypes.d.ts +77 -0
  938. package/dist/types/subscriptionTypes.js +2 -0
  939. package/dist/types/tools.d.ts +45 -1
  940. package/dist/types/typeAliases.d.ts +8 -0
  941. package/dist/types/typeAliases.js +1 -0
  942. package/dist/utils/async/retry.d.ts +4 -33
  943. package/dist/utils/asyncMutex.d.ts +14 -0
  944. package/dist/utils/asyncMutex.js +60 -0
  945. package/dist/utils/errorHandling.d.ts +2 -1
  946. package/dist/utils/errorHandling.js +14 -6
  947. package/dist/utils/fileDetector.d.ts +13 -1
  948. package/dist/utils/fileDetector.js +114 -32
  949. package/dist/utils/imageProcessor.js +7 -7
  950. package/dist/utils/json/safeParse.d.ts +1 -8
  951. package/dist/utils/mcpDefaults.d.ts +1 -1
  952. package/dist/utils/mcpDefaults.js +11 -2
  953. package/dist/utils/messageBuilder.d.ts +5 -5
  954. package/dist/utils/messageBuilder.js +106 -80
  955. package/dist/utils/modelChoices.d.ts +1 -8
  956. package/dist/utils/pdfProcessor.d.ts +1 -25
  957. package/dist/utils/pdfProcessor.js +5 -4
  958. package/dist/utils/pricing.js +28 -5
  959. package/dist/utils/rateLimiter.d.ts +1 -15
  960. package/dist/utils/redis.d.ts +1 -1
  961. package/dist/utils/redis.js +3 -3
  962. package/dist/utils/sanitizers/filename.d.ts +2 -22
  963. package/dist/utils/sanitizers/index.d.ts +4 -2
  964. package/dist/utils/sanitizers/svg.d.ts +1 -11
  965. package/dist/utils/schemaConversion.js +4 -1
  966. package/dist/utils/thinkingConfig.d.ts +1 -33
  967. package/dist/utils/tokenUtils.d.ts +1 -39
  968. package/dist/utils/videoAnalysisProcessor.d.ts +5 -5
  969. package/dist/utils/videoAnalysisProcessor.js +2 -2
  970. package/dist/workflow/config.d.ts +89 -1257
  971. package/dist/workflow/utils/workflowValidation.js +1 -1
  972. package/docs-site/mcp-server/index.js +2 -3
  973. package/package.json +138 -105
  974. package/dist/lib/memory/mem0Initializer.d.ts +0 -46
  975. package/dist/lib/memory/mem0Initializer.js +0 -85
  976. package/dist/memory/mem0Initializer.d.ts +0 -46
  977. package/dist/memory/mem0Initializer.js +0 -84
@@ -0,0 +1,2383 @@
1
+ /**
2
+ * Slide Renderers
3
+ *
4
+ * Standalone render functions for each slide type.
5
+ * Extracted from SlideGenerator to keep functions under 300 lines.
6
+ *
7
+ * @module presentation/slideRenderers
8
+ */
9
+ import { logger } from "../../utils/logger.js";
10
+ import { getBulletOptions, getSlideTypeFormatting } from "./constants.js";
11
+ import { bufferToDataUrl, calculateFontSize, createFormattedTextProps, hasMarkdownFormatting, parseMarkdownText, validateImageBuffer, } from "./utils.js";
12
+ // ============================================================================
13
+ // LAYOUT POSITIONS
14
+ // ============================================================================
15
+ /**
16
+ * Minimum gap between elements (in inches)
17
+ */
18
+ const MIN_GAP = 0.1;
19
+ /**
20
+ * Default text fit option for pptxgenjs
21
+ * 'shrink' = Shrink text to fit within the container
22
+ */
23
+ const DEFAULT_TEXT_FIT = "shrink";
24
+ export const LAYOUT_POSITIONS = {
25
+ margin: { x: 0.5, y: 0.4 },
26
+ title: { x: 0.5, y: 0.4, w: 9, h: 0.8 },
27
+ subtitle: { x: 0.5, y: 1.4, w: 9, h: 0.5 },
28
+ content: { x: 0.5, y: 1.4, w: 9, h: 3.8 },
29
+ contentFull: { x: 0.5, y: 1.4, w: 9, h: 3.8 },
30
+ contentLeft: { x: 0.5, y: 1.4, w: 4.2, h: 3.8 },
31
+ contentRight: { x: 5.3, y: 1.4, w: 4.2, h: 3.8 },
32
+ imageRight: { x: 5.3, y: 1.4, w: 4.2, h: 3.8 },
33
+ imageLeft: { x: 0.5, y: 1.4, w: 4.2, h: 3.8 },
34
+ imageFull: { x: 0, y: 0, w: 10, h: 5.625 },
35
+ imageCentered: { x: 2, y: 1.2, w: 6, h: 3.6 },
36
+ columnLeft: { x: 0.5, y: 1.4, w: 4.2, h: 3.8 },
37
+ columnRight: { x: 5.3, y: 1.4, w: 4.2, h: 3.8 },
38
+ col1: { x: 0.5, y: 1.4, w: 2.8, h: 3.8 },
39
+ col2: { x: 3.5, y: 1.4, w: 2.8, h: 3.8 },
40
+ col3: { x: 6.5, y: 1.4, w: 2.8, h: 3.8 },
41
+ chart: { x: 0.5, y: 1.4, w: 9, h: 3.8 },
42
+ statRow: { y: 2.2, h: 2.5 },
43
+ footer: { x: 0.5, y: 5.2, w: 9, h: 0.3 },
44
+ logo: {
45
+ "top-left": { x: 0.3, y: 0.2 },
46
+ "top-right": { x: 8.5, y: 0.2 },
47
+ "bottom-left": { x: 0.3, y: 5.0 },
48
+ "bottom-right": { x: 8.5, y: 5.0 },
49
+ },
50
+ quote: { x: 1, y: 1.5, w: 8, h: 2.5 },
51
+ quoteAuthor: { x: 1, y: 4.2, w: 8, h: 0.5 },
52
+ };
53
+ /**
54
+ * Map legend position from SlideContent values to pptxgenjs values
55
+ */
56
+ const LEGEND_POS_MAP = {
57
+ top: "t",
58
+ bottom: "b",
59
+ left: "l",
60
+ right: "r",
61
+ };
62
+ // ============================================================================
63
+ // HELPER FUNCTIONS - ENHANCED BACKGROUNDS
64
+ // ============================================================================
65
+ /** Extract theme colors for background (strips # prefix) */
66
+ function extractBackgroundColors(theme) {
67
+ return {
68
+ primary: theme.colors.primary.replace("#", ""),
69
+ secondary: theme.colors.secondary.replace("#", ""),
70
+ accent: theme.colors.accent.replace("#", ""),
71
+ background: theme.colors.background.replace("#", ""),
72
+ };
73
+ }
74
+ /** Blue to purple diagonal gradient effect */
75
+ function addGradientBlueBackground(slide, colors) {
76
+ const { primary, secondary } = colors;
77
+ slide.addShape("rect", {
78
+ x: 0,
79
+ y: 0,
80
+ w: "100%",
81
+ h: "100%",
82
+ fill: { color: "E8F4FD" },
83
+ });
84
+ slide.addShape("rect", {
85
+ x: 0,
86
+ y: 0,
87
+ w: 6,
88
+ h: 3,
89
+ fill: { color: primary, transparency: 85 },
90
+ });
91
+ slide.addShape("rect", {
92
+ x: 0,
93
+ y: 0,
94
+ w: 4,
95
+ h: 2,
96
+ fill: { color: primary, transparency: 75 },
97
+ });
98
+ slide.addShape("rect", {
99
+ x: 5,
100
+ y: 3,
101
+ w: 5,
102
+ h: 2.625,
103
+ fill: { color: secondary, transparency: 85 },
104
+ });
105
+ slide.addShape("rect", {
106
+ x: 7,
107
+ y: 4,
108
+ w: 3,
109
+ h: 1.625,
110
+ fill: { color: secondary, transparency: 75 },
111
+ });
112
+ }
113
+ /** Professional dark blue to teal gradient */
114
+ function addGradientCorporateBackground(slide, colors) {
115
+ const { primary } = colors;
116
+ slide.addShape("rect", {
117
+ x: 0,
118
+ y: 0,
119
+ w: "100%",
120
+ h: "100%",
121
+ fill: { color: "F0F9FF" },
122
+ });
123
+ slide.addShape("rect", {
124
+ x: 0,
125
+ y: 0,
126
+ w: 3,
127
+ h: "100%",
128
+ fill: { color: "1E3A5F", transparency: 92 },
129
+ });
130
+ slide.addShape("rect", {
131
+ x: 0,
132
+ y: 0,
133
+ w: 1.5,
134
+ h: "100%",
135
+ fill: { color: "1E3A5F", transparency: 85 },
136
+ });
137
+ slide.addShape("rect", {
138
+ x: 7,
139
+ y: 0,
140
+ w: 3,
141
+ h: "100%",
142
+ fill: { color: "2E7D32", transparency: 92 },
143
+ });
144
+ slide.addShape("rect", {
145
+ x: 0,
146
+ y: 0,
147
+ w: "100%",
148
+ h: 0.03,
149
+ fill: { color: primary },
150
+ });
151
+ }
152
+ /** Warm orange to pink gradient */
153
+ function addGradientWarmBackground(slide) {
154
+ slide.addShape("rect", {
155
+ x: 0,
156
+ y: 0,
157
+ w: "100%",
158
+ h: "100%",
159
+ fill: { color: "FFF7ED" },
160
+ });
161
+ slide.addShape("rect", {
162
+ x: 0,
163
+ y: 0,
164
+ w: "100%",
165
+ h: 2.5,
166
+ fill: { color: "EA580C", transparency: 90 },
167
+ });
168
+ slide.addShape("rect", {
169
+ x: 0,
170
+ y: 0,
171
+ w: "100%",
172
+ h: 1,
173
+ fill: { color: "EA580C", transparency: 80 },
174
+ });
175
+ slide.addShape("rect", {
176
+ x: 0,
177
+ y: 4.5,
178
+ w: "100%",
179
+ h: 1.125,
180
+ fill: { color: "DB2777", transparency: 88 },
181
+ });
182
+ }
183
+ /** Dark theme with accent glow */
184
+ function addGradientDarkBackground(slide) {
185
+ slide.addShape("rect", {
186
+ x: 0,
187
+ y: 0,
188
+ w: "100%",
189
+ h: "100%",
190
+ fill: { color: "0F172A" },
191
+ });
192
+ slide.addShape("ellipse", {
193
+ x: -2,
194
+ y: -1,
195
+ w: 6,
196
+ h: 4,
197
+ fill: { color: "06B6D4", transparency: 85 },
198
+ });
199
+ slide.addShape("ellipse", {
200
+ x: 7,
201
+ y: 3,
202
+ w: 5,
203
+ h: 4,
204
+ fill: { color: "A855F7", transparency: 85 },
205
+ });
206
+ }
207
+ /** Very subtle professional gradient */
208
+ function addGradientSubtleBackground(slide, colors) {
209
+ const { primary, secondary } = colors;
210
+ slide.addShape("rect", {
211
+ x: 0,
212
+ y: 0,
213
+ w: "100%",
214
+ h: "100%",
215
+ fill: { color: "FAFBFC" },
216
+ });
217
+ slide.addShape("rect", {
218
+ x: 0,
219
+ y: 0,
220
+ w: "100%",
221
+ h: 2,
222
+ fill: { color: primary, transparency: 95 },
223
+ });
224
+ slide.addShape("rect", {
225
+ x: 0,
226
+ y: 4,
227
+ w: "100%",
228
+ h: 1.625,
229
+ fill: { color: secondary, transparency: 96 },
230
+ });
231
+ slide.addShape("rect", {
232
+ x: 0,
233
+ y: 0,
234
+ w: "100%",
235
+ h: 0.02,
236
+ fill: { color: primary },
237
+ });
238
+ }
239
+ /** Geometric shapes pattern */
240
+ function addGeometricBackground(slide, colors) {
241
+ const { primary, secondary, accent, background } = colors;
242
+ slide.addShape("rect", {
243
+ x: 0,
244
+ y: 0,
245
+ w: "100%",
246
+ h: "100%",
247
+ fill: { color: background },
248
+ });
249
+ slide.addShape("rtTriangle", {
250
+ x: 6,
251
+ y: 3,
252
+ w: 4,
253
+ h: 2.625,
254
+ fill: { color: primary, transparency: 90 },
255
+ rotate: 180,
256
+ });
257
+ slide.addShape("rtTriangle", {
258
+ x: 0,
259
+ y: 0,
260
+ w: 2.5,
261
+ h: 2,
262
+ fill: { color: secondary, transparency: 92 },
263
+ });
264
+ slide.addShape("ellipse", {
265
+ x: 8.5,
266
+ y: 0.2,
267
+ w: 1,
268
+ h: 1,
269
+ fill: { color: accent, transparency: 85 },
270
+ });
271
+ slide.addShape("ellipse", {
272
+ x: 0.5,
273
+ y: 4.5,
274
+ w: 0.6,
275
+ h: 0.6,
276
+ fill: { color: primary, transparency: 80 },
277
+ });
278
+ }
279
+ /** Large corner accent shapes */
280
+ function addCornerAccentBackground(slide, colors) {
281
+ const { primary, secondary, background } = colors;
282
+ slide.addShape("rect", {
283
+ x: 0,
284
+ y: 0,
285
+ w: "100%",
286
+ h: "100%",
287
+ fill: { color: background },
288
+ });
289
+ slide.addShape("rect", {
290
+ x: 7,
291
+ y: 0,
292
+ w: 3,
293
+ h: 1.8,
294
+ fill: { color: primary, transparency: 88 },
295
+ });
296
+ slide.addShape("rect", {
297
+ x: 8.5,
298
+ y: 0,
299
+ w: 1.5,
300
+ h: 1,
301
+ fill: { color: primary, transparency: 70 },
302
+ });
303
+ slide.addShape("rect", {
304
+ x: 0,
305
+ y: 4,
306
+ w: 2.5,
307
+ h: 1.625,
308
+ fill: { color: secondary, transparency: 88 },
309
+ });
310
+ slide.addShape("rect", {
311
+ x: 0,
312
+ y: 4.8,
313
+ w: 1.2,
314
+ h: 0.825,
315
+ fill: { color: secondary, transparency: 70 },
316
+ });
317
+ }
318
+ /** Curved wave pattern effect */
319
+ function addWaveBackground(slide, colors) {
320
+ const { primary, secondary, accent } = colors;
321
+ slide.addShape("rect", {
322
+ x: 0,
323
+ y: 0,
324
+ w: "100%",
325
+ h: "100%",
326
+ fill: { color: "F8FAFC" },
327
+ });
328
+ slide.addShape("ellipse", {
329
+ x: -3,
330
+ y: 4,
331
+ w: 8,
332
+ h: 3,
333
+ fill: { color: primary, transparency: 92 },
334
+ });
335
+ slide.addShape("ellipse", {
336
+ x: 2,
337
+ y: 4.5,
338
+ w: 7,
339
+ h: 2.5,
340
+ fill: { color: secondary, transparency: 93 },
341
+ });
342
+ slide.addShape("ellipse", {
343
+ x: 6,
344
+ y: 4.2,
345
+ w: 6,
346
+ h: 3,
347
+ fill: { color: accent, transparency: 94 },
348
+ });
349
+ slide.addShape("rect", {
350
+ x: 0,
351
+ y: 0,
352
+ w: "100%",
353
+ h: 0.03,
354
+ fill: { color: primary },
355
+ });
356
+ }
357
+ /** Split diagonal background */
358
+ function addSplitBackground(slide, colors) {
359
+ const { primary, secondary, background } = colors;
360
+ slide.addShape("rect", {
361
+ x: 0,
362
+ y: 0,
363
+ w: "100%",
364
+ h: "100%",
365
+ fill: { color: background },
366
+ });
367
+ slide.addShape("rect", {
368
+ x: 5,
369
+ y: -1,
370
+ w: 6,
371
+ h: 8,
372
+ fill: { color: primary, transparency: 94 },
373
+ rotate: 15,
374
+ });
375
+ slide.addShape("rect", {
376
+ x: 7,
377
+ y: -1,
378
+ w: 5,
379
+ h: 8,
380
+ fill: { color: secondary, transparency: 92 },
381
+ rotate: 15,
382
+ });
383
+ }
384
+ /** Simple solid with subtle accent */
385
+ function addSolidBackground(slide, colors) {
386
+ const { primary, background } = colors;
387
+ slide.addShape("rect", {
388
+ x: 0,
389
+ y: 0,
390
+ w: "100%",
391
+ h: "100%",
392
+ fill: { color: background },
393
+ });
394
+ slide.addShape("rect", {
395
+ x: 0,
396
+ y: 0,
397
+ w: "100%",
398
+ h: 0.02,
399
+ fill: { color: primary },
400
+ });
401
+ }
402
+ /**
403
+ * Add enhanced background with gradient or multi-color designs
404
+ * Creates visually appealing slides with sophisticated styling
405
+ */
406
+ export function addEnhancedBackground(slide, theme, style = "gradient-subtle") {
407
+ const colors = extractBackgroundColors(theme);
408
+ switch (style) {
409
+ case "gradient-blue":
410
+ addGradientBlueBackground(slide, colors);
411
+ break;
412
+ case "gradient-corporate":
413
+ addGradientCorporateBackground(slide, colors);
414
+ break;
415
+ case "gradient-warm":
416
+ addGradientWarmBackground(slide);
417
+ break;
418
+ case "gradient-dark":
419
+ addGradientDarkBackground(slide);
420
+ break;
421
+ case "gradient-subtle":
422
+ addGradientSubtleBackground(slide, colors);
423
+ break;
424
+ case "geometric":
425
+ addGeometricBackground(slide, colors);
426
+ break;
427
+ case "corner-accent":
428
+ addCornerAccentBackground(slide, colors);
429
+ break;
430
+ case "wave":
431
+ addWaveBackground(slide, colors);
432
+ break;
433
+ case "split":
434
+ addSplitBackground(slide, colors);
435
+ break;
436
+ case "solid":
437
+ default:
438
+ addSolidBackground(slide, colors);
439
+ break;
440
+ }
441
+ }
442
+ /**
443
+ * Add subtle colored background to slides (legacy - use addEnhancedBackground for more options)
444
+ */
445
+ export function addColoredBackground(slide, theme, opacity = 0.05) {
446
+ const primaryColor = theme.colors.primary.replace("#", "");
447
+ slide.addShape("rect", {
448
+ x: 0,
449
+ y: 0,
450
+ w: "100%",
451
+ h: "100%",
452
+ fill: {
453
+ color: primaryColor,
454
+ transparency: (1 - opacity) * 100, // pptx transparency is 0-100 where 100 is fully transparent
455
+ },
456
+ });
457
+ }
458
+ /**
459
+ * Add modern card-style container with border
460
+ */
461
+ export function addCardContainer(slide, pos, theme, borderWidth = 2) {
462
+ // Card background with subtle border
463
+ slide.addShape("rect", {
464
+ x: pos.x,
465
+ y: pos.y,
466
+ w: pos.w,
467
+ h: pos.h,
468
+ fill: {
469
+ color: theme.colors.background.replace("#", ""),
470
+ transparency: 0, // Fully opaque
471
+ },
472
+ line: {
473
+ color: theme.colors.muted.replace("#", ""),
474
+ width: borderWidth,
475
+ },
476
+ });
477
+ }
478
+ /**
479
+ * Add accent bar for visual hierarchy
480
+ */
481
+ export function addAccentBar(slide, pos, theme, position = "left") {
482
+ const barConfig = {
483
+ left: { x: pos.x, y: pos.y, w: 0.1, h: pos.h },
484
+ top: { x: pos.x, y: pos.y, w: pos.w, h: 0.1 },
485
+ bottom: { x: pos.x, y: pos.y + pos.h - 0.1, w: pos.w, h: 0.1 },
486
+ };
487
+ slide.addShape("rect", {
488
+ ...barConfig[position],
489
+ fill: { color: theme.colors.primary.replace("#", "") },
490
+ });
491
+ }
492
+ /**
493
+ * Calculate text width in inches based on font size and character count.
494
+ * Uses typographic metrics for Arial font family.
495
+ *
496
+ * @param text - The text string to measure
497
+ * @param fontSize - Font size in points
498
+ * @param isBold - Whether the text is bold (adds ~10% width)
499
+ * @returns Width in inches
500
+ */
501
+ export function calculateTextWidth(text, fontSize, isBold = false) {
502
+ // For proportional fonts like Arial:
503
+ // - Average character width is approximately 0.42 * em-height for normal text
504
+ // - 1 point = 1/72 inch, so em-height = fontSize / 72 inches
505
+ // - Bold text is approximately 10% wider
506
+ const emHeight = fontSize / 72; // em-height in inches
507
+ const avgCharWidthRatio = 0.42; // Average char width as ratio of em-height (reduced for tighter fit)
508
+ const boldMultiplier = isBold ? 1.1 : 1.0;
509
+ const charWidth = emHeight * avgCharWidthRatio * boldMultiplier;
510
+ return text.length * charWidth;
511
+ }
512
+ export function addTitle(slide, title, theme, showUnderline = true) {
513
+ slide.addText(title, {
514
+ x: LAYOUT_POSITIONS.title.x,
515
+ y: LAYOUT_POSITIONS.title.y,
516
+ w: LAYOUT_POSITIONS.title.w,
517
+ h: LAYOUT_POSITIONS.title.h,
518
+ fontSize: theme.fonts.sizes.heading,
519
+ fontFace: theme.fonts.heading,
520
+ color: theme.colors.text.replace("#", ""),
521
+ bold: true,
522
+ fit: DEFAULT_TEXT_FIT,
523
+ });
524
+ if (showUnderline) {
525
+ // Calculate dynamic underline width based on actual title text and font size
526
+ const textWidth = calculateTextWidth(title, theme.fonts.sizes.heading, true);
527
+ // Constrain to reasonable bounds (min 1.5", max fits within slide margins)
528
+ const maxWidth = LAYOUT_POSITIONS.title.w; // 9 inches - same as title container
529
+ const minWidth = 1.0;
530
+ const calculatedWidth = Math.min(maxWidth, Math.max(minWidth, textWidth));
531
+ slide.addShape("rect", {
532
+ x: LAYOUT_POSITIONS.title.x,
533
+ y: LAYOUT_POSITIONS.title.y + LAYOUT_POSITIONS.title.h + 0.1,
534
+ w: calculatedWidth,
535
+ h: 0.03,
536
+ fill: { color: theme.colors.primary.replace("#", "") },
537
+ });
538
+ }
539
+ }
540
+ /**
541
+ * Add individual bullet items (each as separate text element)
542
+ * This creates cleaner spacing and no bounding box around bullets
543
+ * Useful for column layouts and when you want more control over spacing
544
+ */
545
+ export function addIndividualBullets(options) {
546
+ const { slide, bullets, startX, startY, width, theme, itemSpacing = 0.45, } = options;
547
+ if (!bullets || bullets.length === 0) {
548
+ return;
549
+ }
550
+ // Ensure minimum gap between bullets
551
+ const effectiveSpacing = Math.max(itemSpacing, MIN_GAP * 2);
552
+ bullets.forEach((bullet, index) => {
553
+ // Skip invalid bullets
554
+ if (!bullet || !bullet.text) {
555
+ return;
556
+ }
557
+ const isBold = bullet.bold || bullet.emphasis || false;
558
+ const color = bullet.color?.replace("#", "") || theme.colors.text.replace("#", "");
559
+ // Check if bullet text contains markdown formatting
560
+ if (hasMarkdownFormatting(bullet.text)) {
561
+ // Parse markdown and create rich text runs with bullet prefix
562
+ const segments = parseMarkdownText(bullet.text);
563
+ const textRuns = [
564
+ {
565
+ text: "• ",
566
+ options: {
567
+ fontSize: theme.fonts.sizes.body,
568
+ fontFace: theme.fonts.body,
569
+ color,
570
+ },
571
+ },
572
+ ...createFormattedTextProps(segments, {
573
+ fontSize: theme.fonts.sizes.body,
574
+ fontFace: theme.fonts.body,
575
+ color,
576
+ baseBold: isBold,
577
+ }),
578
+ ];
579
+ slide.addText(textRuns, {
580
+ x: startX,
581
+ y: startY + index * effectiveSpacing,
582
+ w: width,
583
+ h: Math.max(0.4, effectiveSpacing - MIN_GAP),
584
+ fit: DEFAULT_TEXT_FIT,
585
+ });
586
+ }
587
+ else {
588
+ // No markdown - use simple text
589
+ const bulletText = `• ${bullet.text}`;
590
+ slide.addText(bulletText, {
591
+ x: startX,
592
+ y: startY + index * effectiveSpacing,
593
+ w: width,
594
+ h: Math.max(0.4, effectiveSpacing - MIN_GAP),
595
+ fontSize: theme.fonts.sizes.body,
596
+ fontFace: theme.fonts.body,
597
+ color,
598
+ bold: isBold,
599
+ fit: DEFAULT_TEXT_FIT,
600
+ });
601
+ }
602
+ });
603
+ }
604
+ /**
605
+ * Add bullets to a slide with hybrid formatting
606
+ *
607
+ * Priority: bullet-level > slide-level > type-defaults > theme-defaults
608
+ *
609
+ * @param slide - The pptxgenjs slide
610
+ * @param bullets - Array of bullet points (normalized)
611
+ * @param pos - Position and dimensions
612
+ * @param theme - Presentation theme
613
+ * @param slideType - Slide type for default formatting (optional)
614
+ */
615
+ export function addBullets(slide, bullets, pos, theme, slideType = "content", options) {
616
+ if (!bullets || bullets.length === 0) {
617
+ return;
618
+ }
619
+ // Use individual bullets for cleaner spacing (no bounding box)
620
+ if (options?.useIndividualBullets) {
621
+ addIndividualBullets({
622
+ slide,
623
+ bullets,
624
+ startX: pos.x,
625
+ startY: pos.y,
626
+ width: pos.w,
627
+ theme,
628
+ itemSpacing: options.itemSpacing ?? 0.45,
629
+ });
630
+ return;
631
+ }
632
+ // Get hardcoded defaults for this slide type
633
+ const typeDefaults = getSlideTypeFormatting(slideType);
634
+ // Calculate base font size based on bullet count (if not overridden)
635
+ const calculatedFontSize = calculateFontSize(bullets.length, typeDefaults.baseFontSize || theme.fonts.sizes.body);
636
+ const textLines = [];
637
+ bullets.forEach((bullet) => {
638
+ // Skip invalid bullets
639
+ if (!bullet || !bullet.text) {
640
+ return;
641
+ }
642
+ // Priority: bullet-level > type-defaults
643
+ const bulletStyle = bullet.bulletStyle || typeDefaults.bulletStyle || "disc";
644
+ const fontSize = bullet.fontSize || calculatedFontSize;
645
+ const color = bullet.color?.replace("#", "") || theme.colors.text.replace("#", "");
646
+ const isBold = bullet.bold ?? bullet.emphasis ?? false;
647
+ // Get pptxgenjs bullet options based on style
648
+ // If bullet has custom icon, use that instead of style
649
+ let bulletOptions;
650
+ if (bullet.icon) {
651
+ bulletOptions = { code: bullet.icon };
652
+ }
653
+ else {
654
+ bulletOptions = getBulletOptions(bulletStyle);
655
+ }
656
+ // Check if bullet text contains markdown formatting (**bold**, *italic*)
657
+ if (hasMarkdownFormatting(bullet.text)) {
658
+ // Parse markdown and create rich text runs
659
+ const segments = parseMarkdownText(bullet.text);
660
+ const textRuns = createFormattedTextProps(segments, {
661
+ fontSize,
662
+ fontFace: theme.fonts.body,
663
+ color,
664
+ baseBold: isBold,
665
+ });
666
+ textLines.push({
667
+ text: textRuns,
668
+ options: {
669
+ bullet: bulletOptions,
670
+ indentLevel: 0,
671
+ paraSpaceBefore: 6,
672
+ paraSpaceAfter: 6,
673
+ },
674
+ });
675
+ }
676
+ else {
677
+ // No markdown - use simple text
678
+ textLines.push({
679
+ text: bullet.text,
680
+ options: {
681
+ bullet: bulletOptions,
682
+ fontSize,
683
+ fontFace: theme.fonts.body,
684
+ color,
685
+ bold: isBold,
686
+ indentLevel: 0,
687
+ paraSpaceBefore: 6, // Add space before each paragraph (in points)
688
+ paraSpaceAfter: 6, // Add space after each paragraph (in points)
689
+ },
690
+ });
691
+ }
692
+ // Handle sub-bullets (2pt smaller than main bullet)
693
+ if (bullet.subBullets && bullet.subBullets.length > 0) {
694
+ bullet.subBullets.forEach((subBullet) => {
695
+ // Check for markdown in sub-bullets too
696
+ if (hasMarkdownFormatting(subBullet)) {
697
+ const segments = parseMarkdownText(subBullet);
698
+ const textRuns = createFormattedTextProps(segments, {
699
+ fontSize: Math.max(10, fontSize - 2),
700
+ fontFace: theme.fonts.body,
701
+ color: theme.colors.muted.replace("#", ""),
702
+ });
703
+ textLines.push({
704
+ text: textRuns,
705
+ options: {
706
+ bullet: true,
707
+ indentLevel: 1,
708
+ paraSpaceBefore: 3,
709
+ paraSpaceAfter: 3,
710
+ },
711
+ });
712
+ }
713
+ else {
714
+ textLines.push({
715
+ text: subBullet,
716
+ options: {
717
+ bullet: true,
718
+ fontSize: Math.max(10, fontSize - 2),
719
+ fontFace: theme.fonts.body,
720
+ color: theme.colors.muted.replace("#", ""),
721
+ indentLevel: 1,
722
+ paraSpaceBefore: 3,
723
+ paraSpaceAfter: 3,
724
+ },
725
+ });
726
+ }
727
+ });
728
+ }
729
+ });
730
+ slide.addText(textLines, {
731
+ x: pos.x,
732
+ y: pos.y,
733
+ w: pos.w,
734
+ h: pos.h,
735
+ valign: "top",
736
+ fit: DEFAULT_TEXT_FIT,
737
+ });
738
+ }
739
+ export function addImage(slide, imageBuffer, pos) {
740
+ // Validate and get data URL
741
+ const validation = validateImageBuffer(imageBuffer);
742
+ if (!validation.isValid && validation.format === "") {
743
+ logger.warn("[addImage] Invalid image buffer", { error: validation.error });
744
+ return;
745
+ }
746
+ if (!validation.isValid) {
747
+ logger.warn("[addImage] Image validation warning, attempting to add anyway", {
748
+ error: validation.error,
749
+ mimeType: validation.mimeType,
750
+ });
751
+ }
752
+ const dataUrl = bufferToDataUrl(imageBuffer);
753
+ if (!dataUrl) {
754
+ logger.warn("[addImage] Failed to convert buffer to data URL");
755
+ return;
756
+ }
757
+ try {
758
+ slide.addImage({
759
+ data: dataUrl,
760
+ x: pos.x,
761
+ y: pos.y,
762
+ w: pos.w,
763
+ h: pos.h,
764
+ sizing: { type: "cover", w: pos.w, h: pos.h },
765
+ });
766
+ }
767
+ catch (error) {
768
+ logger.error("[addImage] Failed to add image to slide", {
769
+ error: error instanceof Error ? error.message : String(error),
770
+ });
771
+ }
772
+ }
773
+ export function getPptxChartType(slideType) {
774
+ switch (slideType) {
775
+ case "chart-bar":
776
+ return "bar";
777
+ case "chart-line":
778
+ return "line";
779
+ case "chart-pie":
780
+ return "pie";
781
+ case "chart-area":
782
+ return "area";
783
+ default:
784
+ return "bar";
785
+ }
786
+ }
787
+ // ============================================================================
788
+ // SLIDE RENDERERS - OPENING/CLOSING
789
+ // ============================================================================
790
+ export function renderTitleSlide(slide, title, content, theme, imageBuffer) {
791
+ const layout = content.layoutOptions || {};
792
+ const titleOpts = layout.title || {};
793
+ const subtitleOpts = layout.subtitle || {};
794
+ const bgOpts = layout.background || {};
795
+ // Background: image > custom color > theme default (white)
796
+ const imageDataUrl = imageBuffer ? bufferToDataUrl(imageBuffer) : null;
797
+ if (imageDataUrl) {
798
+ slide.background = {
799
+ data: imageDataUrl,
800
+ };
801
+ slide.addShape("rect", {
802
+ x: 0,
803
+ y: 0,
804
+ w: "100%",
805
+ h: "100%",
806
+ fill: { color: "000000", transparency: 40 },
807
+ });
808
+ }
809
+ else if (bgOpts.color ||
810
+ bgOpts.useThemePrimary ||
811
+ bgOpts.useThemeSecondary) {
812
+ const bgColor = bgOpts.useThemePrimary
813
+ ? theme.colors.primary
814
+ : bgOpts.useThemeSecondary
815
+ ? theme.colors.secondary
816
+ : bgOpts.color || theme.colors.background;
817
+ slide.addShape("rect", {
818
+ x: 0,
819
+ y: 0,
820
+ w: 10,
821
+ h: 5.625,
822
+ fill: { color: bgColor.replace("#", "") },
823
+ });
824
+ }
825
+ // Determine text colors based on background
826
+ const hasColoredBg = imageBuffer ||
827
+ bgOpts.color ||
828
+ bgOpts.useThemePrimary ||
829
+ bgOpts.useThemeSecondary;
830
+ const defaultTitleColor = hasColoredBg
831
+ ? "FFFFFF"
832
+ : theme.colors.text.replace("#", "");
833
+ const defaultSubtitleColor = hasColoredBg
834
+ ? "FFFFFF"
835
+ : theme.colors.muted.replace("#", "");
836
+ // Title
837
+ slide.addText(title, {
838
+ x: titleOpts.x ?? 0.5,
839
+ y: titleOpts.y ?? 2,
840
+ w: titleOpts.w ?? 9,
841
+ h: titleOpts.h ?? 1.2,
842
+ fontSize: titleOpts.fontSize ?? theme.fonts.sizes.title,
843
+ fontFace: theme.fonts.heading,
844
+ color: titleOpts.color?.replace("#", "") ?? defaultTitleColor,
845
+ align: titleOpts.align ?? "center",
846
+ bold: true,
847
+ fit: DEFAULT_TEXT_FIT,
848
+ });
849
+ // Subtitle
850
+ if (content.subtitle) {
851
+ slide.addText(content.subtitle, {
852
+ x: subtitleOpts.x ?? 0.5,
853
+ y: subtitleOpts.y ?? 3.3,
854
+ w: subtitleOpts.w ?? 9,
855
+ h: subtitleOpts.h ?? 0.6,
856
+ fontSize: subtitleOpts.fontSize ?? theme.fonts.sizes.subtitle,
857
+ fontFace: theme.fonts.body,
858
+ color: subtitleOpts.color?.replace("#", "") ?? defaultSubtitleColor,
859
+ align: subtitleOpts.align ?? "center",
860
+ fit: DEFAULT_TEXT_FIT,
861
+ });
862
+ }
863
+ }
864
+ export function renderSectionHeaderSlide(slide, title, content, theme) {
865
+ const layout = content.layoutOptions || {};
866
+ const sectionNumOpts = layout.sectionNumber || {};
867
+ const titleOpts = layout.title || {};
868
+ const subtitleOpts = layout.subtitle || {};
869
+ const bgOpts = layout.background || {};
870
+ // Apply background if specified
871
+ if (bgOpts.color) {
872
+ slide.addShape("rect", {
873
+ x: 0,
874
+ y: 0,
875
+ w: 10,
876
+ h: 5.625,
877
+ fill: { color: bgOpts.color.replace("#", "") },
878
+ });
879
+ }
880
+ // Section number
881
+ if (content.sectionNumber) {
882
+ const isWatermark = sectionNumOpts.style === "watermark";
883
+ const isSmall = sectionNumOpts.style === "small";
884
+ slide.addText(String(content.sectionNumber).padStart(2, "0"), {
885
+ x: sectionNumOpts.x ?? (isWatermark ? 5.5 : 0.5),
886
+ y: sectionNumOpts.y ?? (isWatermark ? 0.5 : 1.5),
887
+ w: isWatermark ? 5 : 2,
888
+ h: isWatermark ? 4 : 1,
889
+ fontSize: sectionNumOpts.fontSize ?? (isWatermark ? 200 : isSmall ? 32 : 72),
890
+ fontFace: theme.fonts.heading,
891
+ color: theme.colors.primary.replace("#", ""),
892
+ bold: true,
893
+ align: isWatermark ? "right" : "left",
894
+ transparency: isWatermark ? 70 : 0,
895
+ });
896
+ }
897
+ // Title
898
+ slide.addText(title, {
899
+ x: titleOpts.x ?? 0.5,
900
+ y: titleOpts.y ?? 2.5,
901
+ w: titleOpts.w ?? 9,
902
+ h: titleOpts.h ?? 1,
903
+ fontSize: titleOpts.fontSize ?? theme.fonts.sizes.title,
904
+ fontFace: theme.fonts.heading,
905
+ color: theme.colors.text.replace("#", ""),
906
+ bold: true,
907
+ align: titleOpts.align ?? "left",
908
+ });
909
+ // Subtitle (if provided)
910
+ if (content.subtitle) {
911
+ slide.addText(content.subtitle, {
912
+ x: subtitleOpts.x ?? 0.5,
913
+ y: subtitleOpts.y ?? 3.6,
914
+ w: subtitleOpts.w ?? 8,
915
+ h: subtitleOpts.h ?? 0.6,
916
+ fontSize: subtitleOpts.fontSize ?? theme.fonts.sizes.subtitle,
917
+ fontFace: theme.fonts.body,
918
+ color: theme.colors.muted.replace("#", ""),
919
+ align: subtitleOpts.align ?? "left",
920
+ });
921
+ }
922
+ }
923
+ export function renderThankYouSlide(slide, title, content, theme, imageBuffer) {
924
+ if (imageBuffer) {
925
+ const dataUrl = bufferToDataUrl(imageBuffer);
926
+ if (dataUrl) {
927
+ slide.background = {
928
+ data: dataUrl,
929
+ };
930
+ slide.addShape("rect", {
931
+ x: 0,
932
+ y: 0,
933
+ w: "100%",
934
+ h: "100%",
935
+ fill: { color: "000000", transparency: 40 },
936
+ });
937
+ }
938
+ }
939
+ const textColor = imageBuffer ? "FFFFFF" : theme.colors.text.replace("#", "");
940
+ slide.addText(title || "Thank You!", {
941
+ x: 0.5,
942
+ y: 1.8,
943
+ w: 9,
944
+ h: 1,
945
+ fontSize: theme.fonts.sizes.title,
946
+ fontFace: theme.fonts.heading,
947
+ color: textColor,
948
+ align: "center",
949
+ bold: true,
950
+ fit: DEFAULT_TEXT_FIT,
951
+ });
952
+ if (content.cta) {
953
+ slide.addText(content.cta, {
954
+ x: 0.5,
955
+ y: 2.9,
956
+ w: 9,
957
+ h: 0.5,
958
+ fontSize: theme.fonts.sizes.subtitle,
959
+ fontFace: theme.fonts.body,
960
+ color: imageBuffer ? "FFFFFF" : theme.colors.muted.replace("#", ""),
961
+ align: "center",
962
+ fit: DEFAULT_TEXT_FIT,
963
+ });
964
+ }
965
+ if (content.contactInfo) {
966
+ const contactLines = [];
967
+ if (content.contactInfo.email) {
968
+ contactLines.push(`Email: ${content.contactInfo.email}`);
969
+ }
970
+ if (content.contactInfo.website) {
971
+ contactLines.push(`Web: ${content.contactInfo.website}`);
972
+ }
973
+ if (content.contactInfo.phone) {
974
+ contactLines.push(`Phone: ${content.contactInfo.phone}`);
975
+ }
976
+ if (contactLines.length > 0) {
977
+ slide.addText(contactLines.join(" • "), {
978
+ x: 0.5,
979
+ y: 4.2,
980
+ w: 9,
981
+ h: 0.4,
982
+ fontSize: theme.fonts.sizes.body,
983
+ fontFace: theme.fonts.body,
984
+ color: textColor,
985
+ align: "center",
986
+ fit: DEFAULT_TEXT_FIT,
987
+ });
988
+ }
989
+ if (content.contactInfo.social &&
990
+ Array.isArray(content.contactInfo.social) &&
991
+ content.contactInfo.social.length > 0) {
992
+ const socialText = content.contactInfo.social
993
+ .map((s) => `${s.platform || ""}: ${s.handle || ""}`)
994
+ .join(" • ");
995
+ slide.addText(socialText, {
996
+ x: 0.5,
997
+ y: 4.7,
998
+ w: 9,
999
+ h: 0.3,
1000
+ fontSize: theme.fonts.sizes.caption,
1001
+ fontFace: theme.fonts.body,
1002
+ color: imageBuffer ? "CCCCCC" : theme.colors.muted.replace("#", ""),
1003
+ align: "center",
1004
+ });
1005
+ }
1006
+ }
1007
+ }
1008
+ // ============================================================================
1009
+ // SLIDE RENDERERS - CONTENT
1010
+ // ============================================================================
1011
+ export function renderContentSlide(options) {
1012
+ const { slide, title, content, layout, theme, imageBuffer, slideType = "content", } = options;
1013
+ addTitle(slide, title, theme);
1014
+ const hasImage = imageBuffer && layout.includes("image");
1015
+ const contentPos = hasImage
1016
+ ? layout.includes("left")
1017
+ ? LAYOUT_POSITIONS.contentRight
1018
+ : LAYOUT_POSITIONS.contentLeft
1019
+ : LAYOUT_POSITIONS.contentFull;
1020
+ if (content.bullets && content.bullets.length > 0) {
1021
+ addBullets(slide, content.bullets, contentPos, theme, slideType);
1022
+ }
1023
+ else if (content.body) {
1024
+ slide.addText(content.body, {
1025
+ x: contentPos.x,
1026
+ y: contentPos.y,
1027
+ w: contentPos.w,
1028
+ h: contentPos.h,
1029
+ fontSize: theme.fonts.sizes.body,
1030
+ fontFace: theme.fonts.body,
1031
+ color: theme.colors.text.replace("#", ""),
1032
+ valign: "top",
1033
+ });
1034
+ }
1035
+ if (imageBuffer && hasImage) {
1036
+ const imagePos = layout.includes("left")
1037
+ ? LAYOUT_POSITIONS.imageLeft
1038
+ : LAYOUT_POSITIONS.imageRight;
1039
+ addImage(slide, imageBuffer, imagePos);
1040
+ }
1041
+ }
1042
+ export function renderImageSlide(slide, title, content, layout, theme, imageBuffer) {
1043
+ if (layout === "image-full-overlay" && imageBuffer) {
1044
+ const dataUrl = bufferToDataUrl(imageBuffer);
1045
+ if (dataUrl) {
1046
+ slide.background = {
1047
+ data: dataUrl,
1048
+ };
1049
+ slide.addShape("rect", {
1050
+ x: 0,
1051
+ y: 0,
1052
+ w: "100%",
1053
+ h: "100%",
1054
+ fill: { color: "000000", transparency: 50 },
1055
+ });
1056
+ slide.addText(title, {
1057
+ x: 0.5,
1058
+ y: 4.2,
1059
+ w: 9,
1060
+ h: 1,
1061
+ fontSize: theme.fonts.sizes.heading,
1062
+ fontFace: theme.fonts.heading,
1063
+ color: "FFFFFF",
1064
+ bold: true,
1065
+ fit: DEFAULT_TEXT_FIT,
1066
+ });
1067
+ }
1068
+ else {
1069
+ // Fallback to standard layout if image is invalid
1070
+ addTitle(slide, title, theme);
1071
+ }
1072
+ }
1073
+ else if (layout === "image-centered" || layout === "image-full-overlay") {
1074
+ addTitle(slide, title, theme);
1075
+ if (imageBuffer) {
1076
+ addImage(slide, imageBuffer, LAYOUT_POSITIONS.imageCentered);
1077
+ }
1078
+ else {
1079
+ // Fallback when no image is available - show placeholder with content
1080
+ slide.addShape("rect", {
1081
+ x: 1.5,
1082
+ y: 1.8,
1083
+ w: 7,
1084
+ h: 3.5,
1085
+ fill: { color: theme.colors.muted.replace("#", ""), transparency: 90 },
1086
+ line: {
1087
+ color: theme.colors.muted.replace("#", ""),
1088
+ width: 1,
1089
+ dashType: "dash",
1090
+ },
1091
+ });
1092
+ slide.addText("📷", {
1093
+ x: 1.5,
1094
+ y: 2.8,
1095
+ w: 7,
1096
+ h: 1,
1097
+ fontSize: 48,
1098
+ align: "center",
1099
+ valign: "middle",
1100
+ fit: DEFAULT_TEXT_FIT,
1101
+ });
1102
+ slide.addText("Image not available", {
1103
+ x: 1.5,
1104
+ y: 3.8,
1105
+ w: 7,
1106
+ h: 0.5,
1107
+ fontSize: 12,
1108
+ fontFace: theme.fonts.body,
1109
+ color: theme.colors.muted.replace("#", ""),
1110
+ align: "center",
1111
+ fit: DEFAULT_TEXT_FIT,
1112
+ });
1113
+ }
1114
+ if (content.caption) {
1115
+ slide.addText(content.caption, {
1116
+ x: 0.5,
1117
+ y: 5,
1118
+ w: 9,
1119
+ h: 0.4,
1120
+ fontSize: theme.fonts.sizes.caption,
1121
+ fontFace: theme.fonts.body,
1122
+ color: theme.colors.muted.replace("#", ""),
1123
+ align: "center",
1124
+ fit: DEFAULT_TEXT_FIT,
1125
+ });
1126
+ }
1127
+ }
1128
+ else {
1129
+ renderContentSlide({ slide, title, content, layout, theme, imageBuffer });
1130
+ }
1131
+ }
1132
+ // ============================================================================
1133
+ // SLIDE RENDERERS - COLUMNS
1134
+ // ============================================================================
1135
+ // ============================================================================
1136
+ // SLIDE RENDERERS - COLUMNS (Generic)
1137
+ // ============================================================================
1138
+ /**
1139
+ * Generic column slide renderer
1140
+ * Handles 2, 3, or more columns dynamically
1141
+ * Renders each bullet as separate element (comparison-style)
1142
+ */
1143
+ export function renderColumnSlide(slide, title, columns, theme, options) {
1144
+ addTitle(slide, title, theme, false);
1145
+ const opts = {
1146
+ headerY: options?.headerY ?? 1.3,
1147
+ headerHeight: options?.headerHeight ?? 0.5,
1148
+ bulletsStartY: options?.bulletsStartY ?? 2.0,
1149
+ columnGap: options?.columnGap ?? 0.3,
1150
+ highlightFirstColumn: options?.highlightFirstColumn ?? true,
1151
+ };
1152
+ const numColumns = columns.length;
1153
+ if (numColumns === 0) {
1154
+ return;
1155
+ }
1156
+ // Calculate dynamic column widths
1157
+ const totalWidth = 9; // Available width (10 - 0.5 margin on each side)
1158
+ const totalGaps = (numColumns - 1) * opts.columnGap;
1159
+ const columnWidth = (totalWidth - totalGaps) / numColumns;
1160
+ const startX = 0.5;
1161
+ columns.forEach((col, index) => {
1162
+ if (!col) {
1163
+ return;
1164
+ }
1165
+ const x = startX + index * (columnWidth + opts.columnGap);
1166
+ const isPrimary = opts.highlightFirstColumn && index === 0;
1167
+ // Render header box if title exists
1168
+ if (col.title) {
1169
+ slide.addShape("roundRect", {
1170
+ x,
1171
+ y: opts.headerY,
1172
+ w: columnWidth,
1173
+ h: opts.headerHeight,
1174
+ fill: {
1175
+ color: isPrimary
1176
+ ? theme.colors.primary.replace("#", "")
1177
+ : theme.colors.muted.replace("#", ""),
1178
+ },
1179
+ rectRadius: 0.05,
1180
+ });
1181
+ // Adjust font size based on column count
1182
+ const headerFontSize = numColumns <= 2 ? theme.fonts.sizes.body : theme.fonts.sizes.body - 2;
1183
+ slide.addText(col.title, {
1184
+ x,
1185
+ y: opts.headerY,
1186
+ w: columnWidth,
1187
+ h: opts.headerHeight,
1188
+ fontSize: headerFontSize,
1189
+ fontFace: theme.fonts.heading,
1190
+ color: isPrimary
1191
+ ? theme.colors.textOnPrimary.replace("#", "")
1192
+ : theme.colors.text.replace("#", ""),
1193
+ align: "center",
1194
+ bold: true,
1195
+ valign: "middle",
1196
+ fit: DEFAULT_TEXT_FIT,
1197
+ });
1198
+ }
1199
+ // Render bullets individually (like comparison slide)
1200
+ if (col.bullets && col.bullets.length > 0) {
1201
+ addIndividualBullets({
1202
+ slide,
1203
+ bullets: col.bullets,
1204
+ startX: x,
1205
+ startY: opts.bulletsStartY,
1206
+ width: columnWidth,
1207
+ theme,
1208
+ });
1209
+ }
1210
+ });
1211
+ }
1212
+ export function renderTwoColumnSlide(slide, title, content, layout, theme, imageBuffer) {
1213
+ const columns = [];
1214
+ if (content.leftColumn) {
1215
+ columns.push(content.leftColumn);
1216
+ }
1217
+ if (content.rightColumn) {
1218
+ columns.push(content.rightColumn);
1219
+ }
1220
+ if (columns.length > 0) {
1221
+ renderColumnSlide(slide, title, columns, theme, {
1222
+ highlightFirstColumn: true,
1223
+ });
1224
+ }
1225
+ // Handle image if right column has no bullets
1226
+ if (imageBuffer && !content.rightColumn?.bullets) {
1227
+ addImage(slide, imageBuffer, LAYOUT_POSITIONS.columnRight);
1228
+ }
1229
+ }
1230
+ export function renderThreeColumnSlide(slide, title, content, theme) {
1231
+ const columns = [];
1232
+ if (content.leftColumn) {
1233
+ columns.push(content.leftColumn);
1234
+ }
1235
+ if (content.centerColumn) {
1236
+ columns.push(content.centerColumn);
1237
+ }
1238
+ if (content.rightColumn) {
1239
+ columns.push(content.rightColumn);
1240
+ }
1241
+ if (columns.length > 0) {
1242
+ renderColumnSlide(slide, title, columns, theme, {
1243
+ highlightFirstColumn: true,
1244
+ });
1245
+ }
1246
+ }
1247
+ // ============================================================================
1248
+ // SLIDE RENDERERS - DATA VISUALIZATION
1249
+ // ============================================================================
1250
+ export function renderQuoteSlide(slide, title, content, theme) {
1251
+ slide.addText("\u201C", {
1252
+ x: 0.5,
1253
+ y: 1,
1254
+ w: 1,
1255
+ h: 1,
1256
+ fontSize: 120,
1257
+ fontFace: "Georgia",
1258
+ color: theme.colors.primary.replace("#", ""),
1259
+ fit: DEFAULT_TEXT_FIT,
1260
+ });
1261
+ if (content.quote) {
1262
+ slide.addText(content.quote, {
1263
+ x: LAYOUT_POSITIONS.quote.x,
1264
+ y: LAYOUT_POSITIONS.quote.y,
1265
+ w: LAYOUT_POSITIONS.quote.w,
1266
+ h: LAYOUT_POSITIONS.quote.h,
1267
+ fontSize: theme.fonts.sizes.heading,
1268
+ fontFace: "Georgia",
1269
+ color: theme.colors.text.replace("#", ""),
1270
+ italic: true,
1271
+ valign: "middle",
1272
+ fit: DEFAULT_TEXT_FIT,
1273
+ });
1274
+ }
1275
+ if (content.quoteAuthor) {
1276
+ let authorText = `— ${content.quoteAuthor}`;
1277
+ if (content.quoteAuthorTitle) {
1278
+ authorText += `, ${content.quoteAuthorTitle}`;
1279
+ }
1280
+ slide.addText(authorText, {
1281
+ x: LAYOUT_POSITIONS.quoteAuthor.x,
1282
+ y: LAYOUT_POSITIONS.quoteAuthor.y,
1283
+ w: LAYOUT_POSITIONS.quoteAuthor.w,
1284
+ h: LAYOUT_POSITIONS.quoteAuthor.h,
1285
+ fontSize: theme.fonts.sizes.body,
1286
+ fontFace: theme.fonts.body,
1287
+ color: theme.colors.muted.replace("#", ""),
1288
+ align: "right",
1289
+ fit: DEFAULT_TEXT_FIT,
1290
+ });
1291
+ }
1292
+ }
1293
+ export function renderStatisticsSlide(slide, title, content, theme) {
1294
+ addTitle(slide, title, theme);
1295
+ if (!content.statistics || content.statistics.length === 0) {
1296
+ return;
1297
+ }
1298
+ const stats = content.statistics.slice(0, 4);
1299
+ const statWidth = 9 / stats.length;
1300
+ stats.forEach((stat, index) => {
1301
+ const x = 0.5 + index * statWidth;
1302
+ slide.addText(stat.value, {
1303
+ x,
1304
+ y: LAYOUT_POSITIONS.statRow.y,
1305
+ w: statWidth - 0.2,
1306
+ h: 1.2,
1307
+ fontSize: 48,
1308
+ fontFace: theme.fonts.heading,
1309
+ color: theme.colors.primary.replace("#", ""),
1310
+ bold: true,
1311
+ align: "center",
1312
+ fit: DEFAULT_TEXT_FIT,
1313
+ });
1314
+ slide.addText(stat.label, {
1315
+ x,
1316
+ y: LAYOUT_POSITIONS.statRow.y + 1.3,
1317
+ w: statWidth - 0.2,
1318
+ h: 0.5,
1319
+ fontSize: theme.fonts.sizes.body,
1320
+ fontFace: theme.fonts.body,
1321
+ color: theme.colors.text.replace("#", ""),
1322
+ align: "center",
1323
+ fit: DEFAULT_TEXT_FIT,
1324
+ });
1325
+ if (stat.change || stat.trend) {
1326
+ const trendColor = stat.trend === "up"
1327
+ ? "22C55E"
1328
+ : stat.trend === "down"
1329
+ ? "EF4444"
1330
+ : theme.colors.muted.replace("#", "");
1331
+ // Use simple text indicators instead of Unicode arrows for better compatibility
1332
+ const trendSymbol = stat.trend === "up" ? "(+)" : stat.trend === "down" ? "(-)" : "";
1333
+ slide.addText(`${trendSymbol} ${stat.change || ""}`, {
1334
+ x,
1335
+ y: LAYOUT_POSITIONS.statRow.y + 1.8,
1336
+ w: statWidth - 0.2,
1337
+ h: 0.4,
1338
+ fontSize: theme.fonts.sizes.caption,
1339
+ fontFace: theme.fonts.body,
1340
+ color: trendColor,
1341
+ align: "center",
1342
+ fit: DEFAULT_TEXT_FIT,
1343
+ });
1344
+ }
1345
+ });
1346
+ }
1347
+ export function renderChartSlide(slide, title, content, chartType, theme) {
1348
+ addTitle(slide, title, theme);
1349
+ // Validate chartData exists with valid series
1350
+ if (!content.chartData ||
1351
+ !content.chartData.series ||
1352
+ content.chartData.series.length === 0) {
1353
+ // Add placeholder text for empty chart
1354
+ slide.addText("No chart data available", {
1355
+ x: LAYOUT_POSITIONS.chart.x,
1356
+ y: LAYOUT_POSITIONS.chart.y + 1,
1357
+ w: LAYOUT_POSITIONS.chart.w,
1358
+ h: 1,
1359
+ fontSize: 18,
1360
+ color: theme.colors.muted.replace("#", ""),
1361
+ align: "center",
1362
+ fit: DEFAULT_TEXT_FIT,
1363
+ });
1364
+ return;
1365
+ }
1366
+ // Filter out invalid series (must have name, labels array, and values array)
1367
+ const validSeries = content.chartData.series.filter((series) => series.name &&
1368
+ Array.isArray(series.labels) &&
1369
+ series.labels.length > 0 &&
1370
+ Array.isArray(series.values) &&
1371
+ series.values.length > 0);
1372
+ if (validSeries.length === 0) {
1373
+ slide.addText("Invalid chart data format", {
1374
+ x: LAYOUT_POSITIONS.chart.x,
1375
+ y: LAYOUT_POSITIONS.chart.y + 1,
1376
+ w: LAYOUT_POSITIONS.chart.w,
1377
+ h: 1,
1378
+ fontSize: 18,
1379
+ color: theme.colors.muted.replace("#", ""),
1380
+ align: "center",
1381
+ fit: DEFAULT_TEXT_FIT,
1382
+ });
1383
+ return;
1384
+ }
1385
+ const pptxChartType = getPptxChartType(chartType);
1386
+ const chartData = validSeries.map((series) => ({
1387
+ name: series.name,
1388
+ labels: series.labels,
1389
+ values: series.values,
1390
+ }));
1391
+ slide.addChart(pptxChartType, chartData, {
1392
+ x: LAYOUT_POSITIONS.chart.x,
1393
+ y: LAYOUT_POSITIONS.chart.y,
1394
+ w: LAYOUT_POSITIONS.chart.w,
1395
+ h: LAYOUT_POSITIONS.chart.h,
1396
+ showTitle: !!content.chartData.title,
1397
+ title: content.chartData.title,
1398
+ showLegend: content.chartData.legendPosition !== "none",
1399
+ legendPos: LEGEND_POS_MAP[content.chartData.legendPosition || "bottom"] || "b",
1400
+ showValue: content.chartData.showLabels,
1401
+ chartColors: [
1402
+ theme.colors.primary.replace("#", ""),
1403
+ theme.colors.secondary.replace("#", ""),
1404
+ theme.colors.accent.replace("#", ""),
1405
+ ],
1406
+ });
1407
+ }
1408
+ export function renderTableSlide(slide, title, content, theme) {
1409
+ addTitle(slide, title, theme);
1410
+ if (!content.tableData) {
1411
+ return;
1412
+ }
1413
+ const { headers, rows, hasHeader } = content.tableData;
1414
+ const tableRows = [];
1415
+ if (hasHeader && headers) {
1416
+ tableRows.push(headers.map((header) => ({
1417
+ text: header,
1418
+ options: {
1419
+ bold: true,
1420
+ fill: { color: theme.colors.primary.replace("#", "") },
1421
+ color: theme.colors.textOnPrimary.replace("#", ""),
1422
+ align: "center",
1423
+ },
1424
+ })));
1425
+ }
1426
+ rows.forEach((row, rowIndex) => {
1427
+ tableRows.push(row.map((cell) => ({
1428
+ text: cell.text,
1429
+ options: {
1430
+ fill: { color: rowIndex % 2 === 0 ? "F8FAFC" : "FFFFFF" },
1431
+ color: theme.colors.text.replace("#", ""),
1432
+ align: (cell.align || "left"),
1433
+ },
1434
+ })));
1435
+ });
1436
+ slide.addTable(tableRows, {
1437
+ x: LAYOUT_POSITIONS.chart.x,
1438
+ y: LAYOUT_POSITIONS.chart.y,
1439
+ w: LAYOUT_POSITIONS.chart.w,
1440
+ colW: Array(headers?.length || rows[0]?.length || 1).fill(LAYOUT_POSITIONS.chart.w / (headers?.length || rows[0]?.length || 1)),
1441
+ fontSize: theme.fonts.sizes.body - 2,
1442
+ fontFace: theme.fonts.body,
1443
+ border: { pt: 0.5, color: "E2E8F0" },
1444
+ autoPage: true,
1445
+ });
1446
+ if (content.tableData.caption) {
1447
+ slide.addText(content.tableData.caption, {
1448
+ x: 0.5,
1449
+ y: 5.1,
1450
+ w: 9,
1451
+ h: 0.3,
1452
+ fontSize: theme.fonts.sizes.caption,
1453
+ fontFace: theme.fonts.body,
1454
+ color: theme.colors.muted.replace("#", ""),
1455
+ align: "center",
1456
+ });
1457
+ }
1458
+ }
1459
+ // ============================================================================
1460
+ // SLIDE RENDERERS - PROCESS & TIMELINE
1461
+ // ============================================================================
1462
+ export function renderTimelineSlide(slide, title, content, theme) {
1463
+ addTitle(slide, title, theme);
1464
+ if (!content.timeline?.items) {
1465
+ return;
1466
+ }
1467
+ const items = content.timeline.items.slice(0, 5);
1468
+ const isHorizontal = content.timeline.orientation !== "vertical";
1469
+ if (isHorizontal) {
1470
+ renderHorizontalTimeline(slide, items, theme);
1471
+ }
1472
+ else {
1473
+ renderVerticalTimeline(slide, items, theme);
1474
+ }
1475
+ }
1476
+ function renderHorizontalTimeline(slide, items, theme) {
1477
+ const itemWidth = 8 / items.length;
1478
+ const lineY = 2.8;
1479
+ slide.addShape("rect", {
1480
+ x: 1,
1481
+ y: lineY,
1482
+ w: 8,
1483
+ h: 0.02,
1484
+ fill: { color: theme.colors.primary.replace("#", "") },
1485
+ });
1486
+ items.forEach((item, index) => {
1487
+ const x = 1 + index * itemWidth + itemWidth / 2 - 0.15;
1488
+ slide.addShape("ellipse", {
1489
+ x,
1490
+ y: lineY - 0.15,
1491
+ w: 0.3,
1492
+ h: 0.3,
1493
+ fill: { color: theme.colors.primary.replace("#", "") },
1494
+ });
1495
+ slide.addText(item.date, {
1496
+ x: x - itemWidth / 2 + 0.15,
1497
+ y: lineY - 0.8,
1498
+ w: itemWidth,
1499
+ h: 0.4,
1500
+ fontSize: theme.fonts.sizes.caption,
1501
+ fontFace: theme.fonts.body,
1502
+ color: theme.colors.primary.replace("#", ""),
1503
+ align: "center",
1504
+ bold: true,
1505
+ fit: DEFAULT_TEXT_FIT,
1506
+ });
1507
+ slide.addText(item.title, {
1508
+ x: x - itemWidth / 2 + 0.15,
1509
+ y: lineY + 0.4,
1510
+ w: itemWidth,
1511
+ h: 0.4,
1512
+ fontSize: theme.fonts.sizes.body,
1513
+ fontFace: theme.fonts.heading,
1514
+ color: theme.colors.text.replace("#", ""),
1515
+ align: "center",
1516
+ bold: true,
1517
+ fit: DEFAULT_TEXT_FIT,
1518
+ });
1519
+ if (item.description) {
1520
+ slide.addText(item.description, {
1521
+ x: x - itemWidth / 2 + 0.15,
1522
+ y: lineY + 0.85,
1523
+ w: itemWidth,
1524
+ h: 0.8,
1525
+ fontSize: theme.fonts.sizes.caption,
1526
+ fontFace: theme.fonts.body,
1527
+ color: theme.colors.muted.replace("#", ""),
1528
+ align: "center",
1529
+ fit: DEFAULT_TEXT_FIT,
1530
+ });
1531
+ }
1532
+ });
1533
+ }
1534
+ function renderVerticalTimeline(slide, items, theme) {
1535
+ const itemHeight = 3 / items.length;
1536
+ const lineX = 1.5;
1537
+ slide.addShape("rect", {
1538
+ x: lineX,
1539
+ y: 1.5,
1540
+ w: 0.04,
1541
+ h: 3.5,
1542
+ fill: { color: theme.colors.primary.replace("#", "") },
1543
+ });
1544
+ items.forEach((item, index) => {
1545
+ const y = 1.7 + index * itemHeight;
1546
+ slide.addShape("ellipse", {
1547
+ x: lineX - 0.12,
1548
+ y,
1549
+ w: 0.28,
1550
+ h: 0.28,
1551
+ fill: { color: theme.colors.primary.replace("#", "") },
1552
+ });
1553
+ slide.addText(item.date, {
1554
+ x: 0.3,
1555
+ y: y - 0.1,
1556
+ w: 1,
1557
+ h: 0.3,
1558
+ fontSize: theme.fonts.sizes.caption,
1559
+ fontFace: theme.fonts.body,
1560
+ color: theme.colors.primary.replace("#", ""),
1561
+ bold: true,
1562
+ fit: DEFAULT_TEXT_FIT,
1563
+ });
1564
+ slide.addText(item.title, {
1565
+ x: 2,
1566
+ y: y - 0.1,
1567
+ w: 7,
1568
+ h: 0.4,
1569
+ fontSize: theme.fonts.sizes.body,
1570
+ fontFace: theme.fonts.heading,
1571
+ color: theme.colors.text.replace("#", ""),
1572
+ bold: true,
1573
+ fit: DEFAULT_TEXT_FIT,
1574
+ });
1575
+ if (item.description) {
1576
+ slide.addText(item.description, {
1577
+ x: 2,
1578
+ y: y + 0.3,
1579
+ w: 7,
1580
+ h: 0.4,
1581
+ fontSize: theme.fonts.sizes.caption,
1582
+ fontFace: theme.fonts.body,
1583
+ color: theme.colors.muted.replace("#", ""),
1584
+ fit: DEFAULT_TEXT_FIT,
1585
+ });
1586
+ }
1587
+ });
1588
+ }
1589
+ export function renderProcessFlowSlide(slide, title, content, theme) {
1590
+ addTitle(slide, title, theme);
1591
+ if (!content.processSteps) {
1592
+ return;
1593
+ }
1594
+ const steps = content.processSteps.slice(0, 5);
1595
+ const stepWidth = 8 / steps.length;
1596
+ steps.forEach((step, index) => {
1597
+ const x = 1 + index * stepWidth;
1598
+ const boxWidth = stepWidth - 0.4;
1599
+ slide.addShape("roundRect", {
1600
+ x,
1601
+ y: 2,
1602
+ w: boxWidth,
1603
+ h: 2,
1604
+ fill: { color: theme.colors.primary.replace("#", "") },
1605
+ rectRadius: 0.1,
1606
+ });
1607
+ slide.addText(String(step.step), {
1608
+ x,
1609
+ y: 2.1,
1610
+ w: boxWidth,
1611
+ h: 0.5,
1612
+ fontSize: 24,
1613
+ fontFace: theme.fonts.heading,
1614
+ color: theme.colors.textOnPrimary.replace("#", ""),
1615
+ align: "center",
1616
+ bold: true,
1617
+ fit: DEFAULT_TEXT_FIT,
1618
+ });
1619
+ slide.addText(step.title, {
1620
+ x,
1621
+ y: 2.6,
1622
+ w: boxWidth,
1623
+ h: 0.5,
1624
+ fontSize: theme.fonts.sizes.body,
1625
+ fontFace: theme.fonts.heading,
1626
+ color: theme.colors.textOnPrimary.replace("#", ""),
1627
+ align: "center",
1628
+ bold: true,
1629
+ fit: DEFAULT_TEXT_FIT,
1630
+ });
1631
+ if (step.description) {
1632
+ slide.addText(step.description, {
1633
+ x,
1634
+ y: 3.2,
1635
+ w: boxWidth,
1636
+ h: 0.7,
1637
+ fontSize: theme.fonts.sizes.caption,
1638
+ fontFace: theme.fonts.body,
1639
+ color: theme.colors.textOnPrimary.replace("#", ""),
1640
+ align: "center",
1641
+ fit: DEFAULT_TEXT_FIT,
1642
+ });
1643
+ }
1644
+ if (index < steps.length - 1) {
1645
+ // Use rightArrow shape for better visibility
1646
+ slide.addShape("rightArrow", {
1647
+ x: x + boxWidth + 0.02,
1648
+ y: 2.85,
1649
+ w: 0.35,
1650
+ h: 0.3,
1651
+ fill: { color: theme.colors.primary.replace("#", "") },
1652
+ });
1653
+ }
1654
+ });
1655
+ }
1656
+ // ============================================================================
1657
+ // SLIDE RENDERERS - COMPARISON & FEATURES
1658
+ // ============================================================================
1659
+ export function renderComparisonSlide(slide, title, content, theme) {
1660
+ addTitle(slide, title, theme, false);
1661
+ if (!content.comparison?.columns) {
1662
+ return;
1663
+ }
1664
+ const columns = content.comparison.columns.slice(0, 2);
1665
+ const columnWidth = 4.2;
1666
+ // Calculate available height for bullet items (from y=2.0 to y=5.0 = 3.0 inches)
1667
+ const contentStartY = 2.0;
1668
+ const contentEndY = 5.0;
1669
+ const availableHeight = contentEndY - contentStartY;
1670
+ // Find max items across columns to calculate consistent spacing
1671
+ const maxItems = Math.max(...columns.map((col) => Math.min(col.items?.length || 0, 6)));
1672
+ // Calculate item height with minimum gap (at least 0.1 inch gap between items)
1673
+ const itemHeight = maxItems > 0
1674
+ ? Math.min(0.7, (availableHeight - MIN_GAP * maxItems) / maxItems)
1675
+ : 0.5;
1676
+ const effectiveSpacing = itemHeight + MIN_GAP;
1677
+ columns.forEach((col, index) => {
1678
+ const x = 0.5 + index * 4.8;
1679
+ slide.addShape("roundRect", {
1680
+ x,
1681
+ y: 1.4,
1682
+ w: columnWidth,
1683
+ h: 0.5,
1684
+ fill: {
1685
+ color: col.highlight
1686
+ ? theme.colors.primary.replace("#", "")
1687
+ : theme.colors.muted.replace("#", ""),
1688
+ },
1689
+ rectRadius: 0.05,
1690
+ });
1691
+ slide.addText(col.title, {
1692
+ x,
1693
+ y: 1.4,
1694
+ w: columnWidth,
1695
+ h: 0.5,
1696
+ fontSize: theme.fonts.sizes.body,
1697
+ fontFace: theme.fonts.heading,
1698
+ color: col.highlight
1699
+ ? theme.colors.textOnPrimary.replace("#", "")
1700
+ : theme.colors.text.replace("#", ""),
1701
+ align: "center",
1702
+ bold: true,
1703
+ valign: "middle",
1704
+ fit: DEFAULT_TEXT_FIT,
1705
+ });
1706
+ // Limit items to prevent overflow (max 6 items)
1707
+ const items = (col.items || []).slice(0, 6);
1708
+ // Calculate font size based on item count (smaller font for more items)
1709
+ const fontSize = items.length > 4
1710
+ ? Math.max(12, theme.fonts.sizes.body - 2)
1711
+ : theme.fonts.sizes.body;
1712
+ items.forEach((item, itemIndex) => {
1713
+ // Check for markdown formatting
1714
+ if (hasMarkdownFormatting(item)) {
1715
+ const segments = parseMarkdownText(item);
1716
+ const textRuns = [
1717
+ {
1718
+ text: "• ",
1719
+ options: {
1720
+ fontSize,
1721
+ fontFace: theme.fonts.body,
1722
+ color: theme.colors.text.replace("#", ""),
1723
+ },
1724
+ },
1725
+ ...createFormattedTextProps(segments, {
1726
+ fontSize,
1727
+ fontFace: theme.fonts.body,
1728
+ color: theme.colors.text.replace("#", ""),
1729
+ }),
1730
+ ];
1731
+ slide.addText(textRuns, {
1732
+ x: x + 0.2,
1733
+ y: contentStartY + itemIndex * effectiveSpacing,
1734
+ w: columnWidth - 0.4,
1735
+ h: itemHeight,
1736
+ valign: "top",
1737
+ fit: DEFAULT_TEXT_FIT,
1738
+ });
1739
+ }
1740
+ else {
1741
+ slide.addText(`• ${item}`, {
1742
+ x: x + 0.2,
1743
+ y: contentStartY + itemIndex * effectiveSpacing,
1744
+ w: columnWidth - 0.4,
1745
+ h: itemHeight,
1746
+ fontSize,
1747
+ fontFace: theme.fonts.body,
1748
+ color: theme.colors.text.replace("#", ""),
1749
+ valign: "top",
1750
+ fit: DEFAULT_TEXT_FIT,
1751
+ });
1752
+ }
1753
+ });
1754
+ });
1755
+ }
1756
+ export function renderFeaturesSlide(slide, title, content, theme) {
1757
+ addTitle(slide, title, theme);
1758
+ const rawFeatures = content.features || [];
1759
+ const rawIcons = content.icons || [];
1760
+ const normalizedFeatures = rawFeatures.length > 0
1761
+ ? rawFeatures
1762
+ : rawIcons.map((icon) => ({
1763
+ title: icon.label,
1764
+ description: icon.description || "",
1765
+ icon: icon.icon,
1766
+ }));
1767
+ if (normalizedFeatures.length === 0) {
1768
+ return;
1769
+ }
1770
+ const itemsPerRow = Math.min(normalizedFeatures.length, 3);
1771
+ const itemWidth = 9 / itemsPerRow;
1772
+ normalizedFeatures
1773
+ .slice(0, 6)
1774
+ .forEach((feature, index) => {
1775
+ const row = Math.floor(index / itemsPerRow);
1776
+ const col = index % itemsPerRow;
1777
+ const x = 0.5 + col * itemWidth;
1778
+ const y = 1.6 + row * 1.8;
1779
+ if (feature.icon) {
1780
+ const codePoint = parseInt(feature.icon, 16);
1781
+ if (!Number.isNaN(codePoint) &&
1782
+ codePoint >= 0 &&
1783
+ codePoint <= 0x10ffff) {
1784
+ const iconChar = String.fromCodePoint(codePoint);
1785
+ slide.addText(iconChar, {
1786
+ x,
1787
+ y,
1788
+ w: itemWidth - 0.2,
1789
+ h: 0.6,
1790
+ fontSize: 36,
1791
+ fontFace: "Segoe UI Emoji",
1792
+ color: theme.colors.primary.replace("#", ""),
1793
+ align: "center",
1794
+ fit: DEFAULT_TEXT_FIT,
1795
+ });
1796
+ }
1797
+ }
1798
+ slide.addText(feature.title, {
1799
+ x,
1800
+ y: y + 0.6,
1801
+ w: itemWidth - 0.2,
1802
+ h: 0.4,
1803
+ fontSize: theme.fonts.sizes.body,
1804
+ fontFace: theme.fonts.heading,
1805
+ color: theme.colors.text.replace("#", ""),
1806
+ align: "center",
1807
+ bold: true,
1808
+ fit: DEFAULT_TEXT_FIT,
1809
+ });
1810
+ if (feature.description) {
1811
+ slide.addText(feature.description, {
1812
+ x,
1813
+ y: y + 1,
1814
+ w: itemWidth - 0.2,
1815
+ h: 0.6,
1816
+ fontSize: theme.fonts.sizes.caption,
1817
+ fontFace: theme.fonts.body,
1818
+ color: theme.colors.muted.replace("#", ""),
1819
+ align: "center",
1820
+ fit: DEFAULT_TEXT_FIT,
1821
+ });
1822
+ }
1823
+ });
1824
+ }
1825
+ export function renderTeamSlide(slide, title, content, theme) {
1826
+ addTitle(slide, title, theme);
1827
+ if (!content.teamMembers) {
1828
+ return;
1829
+ }
1830
+ const members = content.teamMembers.slice(0, 4);
1831
+ const memberWidth = 9 / members.length;
1832
+ members.forEach((member, index) => {
1833
+ const x = 0.5 + index * memberWidth;
1834
+ slide.addShape("ellipse", {
1835
+ x: x + (memberWidth - 1.5) / 2,
1836
+ y: 1.6,
1837
+ w: 1.5,
1838
+ h: 1.5,
1839
+ fill: { color: theme.colors.muted.replace("#", "") },
1840
+ });
1841
+ const initials = member.name
1842
+ .split(" ")
1843
+ .map((n) => n[0])
1844
+ .join("")
1845
+ .substring(0, 2);
1846
+ slide.addText(initials, {
1847
+ x: x + (memberWidth - 1.5) / 2,
1848
+ y: 2,
1849
+ w: 1.5,
1850
+ h: 0.7,
1851
+ fontSize: 28,
1852
+ fontFace: theme.fonts.heading,
1853
+ color: "FFFFFF",
1854
+ align: "center",
1855
+ bold: true,
1856
+ fit: DEFAULT_TEXT_FIT,
1857
+ });
1858
+ slide.addText(member.name, {
1859
+ x,
1860
+ y: 3.3,
1861
+ w: memberWidth - 0.2,
1862
+ h: 0.4,
1863
+ fontSize: theme.fonts.sizes.body,
1864
+ fontFace: theme.fonts.heading,
1865
+ color: theme.colors.text.replace("#", ""),
1866
+ align: "center",
1867
+ bold: true,
1868
+ fit: DEFAULT_TEXT_FIT,
1869
+ });
1870
+ slide.addText(member.role, {
1871
+ x,
1872
+ y: 3.7,
1873
+ w: memberWidth - 0.2,
1874
+ h: 0.3,
1875
+ fontSize: theme.fonts.sizes.caption,
1876
+ fontFace: theme.fonts.body,
1877
+ color: theme.colors.muted.replace("#", ""),
1878
+ align: "center",
1879
+ fit: DEFAULT_TEXT_FIT,
1880
+ });
1881
+ });
1882
+ }
1883
+ export function renderConclusionSlide(slide, title, content, theme) {
1884
+ addTitle(slide, title, theme);
1885
+ if (content.bullets) {
1886
+ const checkmarkBullets = content.bullets.map((bullet) => ({
1887
+ ...bullet,
1888
+ icon: bullet.icon || "2713",
1889
+ }));
1890
+ addBullets(slide, checkmarkBullets, LAYOUT_POSITIONS.contentFull, theme, "conclusion");
1891
+ }
1892
+ if (content.cta) {
1893
+ slide.addText(content.cta, {
1894
+ x: 0.5,
1895
+ y: 4.6,
1896
+ w: 9,
1897
+ h: 0.5,
1898
+ fontSize: theme.fonts.sizes.heading - 4,
1899
+ fontFace: theme.fonts.heading,
1900
+ color: theme.colors.primary.replace("#", ""),
1901
+ align: "center",
1902
+ bold: true,
1903
+ fit: DEFAULT_TEXT_FIT,
1904
+ });
1905
+ }
1906
+ }
1907
+ // ============================================================================
1908
+ // COMPOSITE/DASHBOARD SLIDE RENDERERS
1909
+ // Mixed content types on a single slide
1910
+ // ============================================================================
1911
+ /**
1912
+ * Predefined grid layouts for composite slides
1913
+ */
1914
+ export const COMPOSITE_LAYOUTS = {
1915
+ // Two halves side by side
1916
+ "left-right": [
1917
+ { x: 0.5, y: 1.4, w: 4.3, h: 3.6 },
1918
+ { x: 5.2, y: 1.4, w: 4.3, h: 3.6 },
1919
+ ],
1920
+ // Top and bottom
1921
+ "top-bottom": [
1922
+ { x: 0.5, y: 1.2, w: 9, h: 1.8 },
1923
+ { x: 0.5, y: 3.2, w: 9, h: 2.0 },
1924
+ ],
1925
+ // Three columns
1926
+ "three-cols": [
1927
+ { x: 0.5, y: 1.4, w: 2.8, h: 3.6 },
1928
+ { x: 3.5, y: 1.4, w: 2.8, h: 3.6 },
1929
+ { x: 6.5, y: 1.4, w: 2.8, h: 3.6 },
1930
+ ],
1931
+ // Four quadrants
1932
+ quadrants: [
1933
+ { x: 0.5, y: 1.2, w: 4.3, h: 1.8 },
1934
+ { x: 5.2, y: 1.2, w: 4.3, h: 1.8 },
1935
+ { x: 0.5, y: 3.2, w: 4.3, h: 1.8 },
1936
+ { x: 5.2, y: 3.2, w: 4.3, h: 1.8 },
1937
+ ],
1938
+ // Five boxes (2 on top, 3 on bottom)
1939
+ "five-boxes": [
1940
+ { x: 0.5, y: 1.2, w: 4.3, h: 1.6 },
1941
+ { x: 5.2, y: 1.2, w: 4.3, h: 1.6 },
1942
+ { x: 0.5, y: 3.0, w: 2.8, h: 2.0 },
1943
+ { x: 3.5, y: 3.0, w: 2.8, h: 2.0 },
1944
+ { x: 6.5, y: 3.0, w: 2.8, h: 2.0 },
1945
+ ],
1946
+ // Six boxes (2x3 grid)
1947
+ "six-boxes": [
1948
+ { x: 0.5, y: 1.2, w: 2.8, h: 1.6 },
1949
+ { x: 3.5, y: 1.2, w: 2.8, h: 1.6 },
1950
+ { x: 6.5, y: 1.2, w: 2.8, h: 1.6 },
1951
+ { x: 0.5, y: 3.0, w: 2.8, h: 1.8 },
1952
+ { x: 3.5, y: 3.0, w: 2.8, h: 1.8 },
1953
+ { x: 6.5, y: 3.0, w: 2.8, h: 1.8 },
1954
+ ],
1955
+ // Main content left, sidebar right
1956
+ "main-sidebar": [
1957
+ { x: 0.5, y: 1.4, w: 5.8, h: 3.6 },
1958
+ { x: 6.5, y: 1.4, w: 3.0, h: 3.6 },
1959
+ ],
1960
+ // Wide top, three boxes bottom
1961
+ "top-three": [
1962
+ { x: 0.5, y: 1.2, w: 9, h: 1.6 },
1963
+ { x: 0.5, y: 3.0, w: 2.8, h: 2.0 },
1964
+ { x: 3.5, y: 3.0, w: 2.8, h: 2.0 },
1965
+ { x: 6.5, y: 3.0, w: 2.8, h: 2.0 },
1966
+ ],
1967
+ };
1968
+ /**
1969
+ * Render a content box with background
1970
+ */
1971
+ function renderContentBox(slide, pos, title, theme, isPrimary = false) {
1972
+ // Add background box
1973
+ slide.addShape("roundRect", {
1974
+ x: pos.x,
1975
+ y: pos.y,
1976
+ w: pos.w,
1977
+ h: pos.h,
1978
+ fill: {
1979
+ color: isPrimary
1980
+ ? theme.colors.primary.replace("#", "") + "15"
1981
+ : "F8F9FA",
1982
+ },
1983
+ line: {
1984
+ color: isPrimary ? theme.colors.primary.replace("#", "") : "E5E7EB",
1985
+ width: 1,
1986
+ },
1987
+ rectRadius: 0.1,
1988
+ });
1989
+ let contentY = pos.y + 0.15;
1990
+ let contentH = pos.h - 0.3;
1991
+ // Add title if provided
1992
+ if (title) {
1993
+ slide.addText(title, {
1994
+ x: pos.x + 0.15,
1995
+ y: pos.y + 0.1,
1996
+ w: pos.w - 0.3,
1997
+ h: 0.35,
1998
+ fontSize: 14,
1999
+ fontFace: theme.fonts.heading,
2000
+ color: isPrimary
2001
+ ? theme.colors.primary.replace("#", "")
2002
+ : theme.colors.text.replace("#", ""),
2003
+ bold: true,
2004
+ fit: DEFAULT_TEXT_FIT,
2005
+ });
2006
+ contentY = pos.y + 0.45;
2007
+ contentH = pos.h - 0.55;
2008
+ }
2009
+ return { contentY, contentH };
2010
+ }
2011
+ /**
2012
+ * Render bullets in a zone
2013
+ */
2014
+ function renderBulletsInZone(slide, bullets, pos, theme, contentY, contentH) {
2015
+ if (!bullets || bullets.length === 0) {
2016
+ return;
2017
+ }
2018
+ const fontSize = Math.max(11, Math.min(14, 16 - bullets.length));
2019
+ const color = theme.colors.text.replace("#", "");
2020
+ bullets.forEach((bullet, idx) => {
2021
+ // Skip invalid bullets
2022
+ if (!bullet || !bullet.text) {
2023
+ return;
2024
+ }
2025
+ const bulletY = contentY + idx * (contentH / bullets.length);
2026
+ // Check if bullet text contains markdown formatting
2027
+ if (hasMarkdownFormatting(bullet.text)) {
2028
+ const segments = parseMarkdownText(bullet.text);
2029
+ const textRuns = [
2030
+ {
2031
+ text: "• ",
2032
+ options: { fontSize, fontFace: theme.fonts.body, color },
2033
+ },
2034
+ ...createFormattedTextProps(segments, {
2035
+ fontSize,
2036
+ fontFace: theme.fonts.body,
2037
+ color,
2038
+ }),
2039
+ ];
2040
+ slide.addText(textRuns, {
2041
+ x: pos.x + 0.15,
2042
+ y: bulletY,
2043
+ w: pos.w - 0.3,
2044
+ h: contentH / bullets.length,
2045
+ valign: "top",
2046
+ fit: DEFAULT_TEXT_FIT,
2047
+ });
2048
+ }
2049
+ else {
2050
+ slide.addText(`• ${bullet.text}`, {
2051
+ x: pos.x + 0.15,
2052
+ y: bulletY,
2053
+ w: pos.w - 0.3,
2054
+ h: contentH / bullets.length,
2055
+ fontSize,
2056
+ fontFace: theme.fonts.body,
2057
+ color,
2058
+ valign: "top",
2059
+ fit: DEFAULT_TEXT_FIT,
2060
+ });
2061
+ }
2062
+ });
2063
+ }
2064
+ /**
2065
+ * Render mini stat in a zone
2066
+ */
2067
+ function renderStatInZone(slide, stat, pos, theme, contentY, contentH) {
2068
+ // Value
2069
+ slide.addText(stat.value, {
2070
+ x: pos.x,
2071
+ y: contentY,
2072
+ w: pos.w,
2073
+ h: contentH * 0.6,
2074
+ fontSize: Math.min(32, pos.w * 8),
2075
+ fontFace: theme.fonts.heading,
2076
+ color: theme.colors.primary.replace("#", ""),
2077
+ bold: true,
2078
+ align: "center",
2079
+ valign: "bottom",
2080
+ fit: DEFAULT_TEXT_FIT,
2081
+ });
2082
+ // Label
2083
+ slide.addText(stat.label, {
2084
+ x: pos.x,
2085
+ y: contentY + contentH * 0.6,
2086
+ w: pos.w,
2087
+ h: contentH * 0.4,
2088
+ fontSize: 11,
2089
+ fontFace: theme.fonts.body,
2090
+ color: theme.colors.muted.replace("#", ""),
2091
+ align: "center",
2092
+ valign: "top",
2093
+ fit: DEFAULT_TEXT_FIT,
2094
+ });
2095
+ }
2096
+ /**
2097
+ * Render icon box in a zone
2098
+ */
2099
+ function renderIconBoxInZone(options) {
2100
+ const { slide, icon, label, description, pos, theme, contentY, contentH } = options;
2101
+ // Icon circle
2102
+ const iconSize = Math.min(0.6, pos.w * 0.2);
2103
+ slide.addShape("ellipse", {
2104
+ x: pos.x + (pos.w - iconSize) / 2,
2105
+ y: contentY,
2106
+ w: iconSize,
2107
+ h: iconSize,
2108
+ fill: { color: theme.colors.primary.replace("#", "") },
2109
+ });
2110
+ // Icon text (Unicode)
2111
+ const codePoint = parseInt(icon, 16);
2112
+ if (Number.isNaN(codePoint) || codePoint < 0 || codePoint > 0x10ffff) {
2113
+ logger.warn("[renderIconBoxInZone] Invalid icon code", { icon });
2114
+ return;
2115
+ }
2116
+ const iconChar = String.fromCodePoint(codePoint);
2117
+ slide.addText(iconChar, {
2118
+ x: pos.x + (pos.w - iconSize) / 2,
2119
+ y: contentY,
2120
+ w: iconSize,
2121
+ h: iconSize,
2122
+ fontSize: 16,
2123
+ color: "FFFFFF",
2124
+ align: "center",
2125
+ valign: "middle",
2126
+ fit: DEFAULT_TEXT_FIT,
2127
+ });
2128
+ // Label
2129
+ slide.addText(label, {
2130
+ x: pos.x,
2131
+ y: contentY + iconSize + 0.1,
2132
+ w: pos.w,
2133
+ h: 0.3,
2134
+ fontSize: 12,
2135
+ fontFace: theme.fonts.heading,
2136
+ color: theme.colors.text.replace("#", ""),
2137
+ bold: true,
2138
+ align: "center",
2139
+ fit: DEFAULT_TEXT_FIT,
2140
+ });
2141
+ // Description
2142
+ if (description) {
2143
+ slide.addText(description, {
2144
+ x: pos.x + 0.1,
2145
+ y: contentY + iconSize + 0.4,
2146
+ w: pos.w - 0.2,
2147
+ h: contentH - iconSize - 0.5,
2148
+ fontSize: 10,
2149
+ fontFace: theme.fonts.body,
2150
+ color: theme.colors.muted.replace("#", ""),
2151
+ align: "center",
2152
+ fit: DEFAULT_TEXT_FIT,
2153
+ });
2154
+ }
2155
+ }
2156
+ /**
2157
+ * Render a mini chart in a zone
2158
+ */
2159
+ function renderMiniChartInZone(slide, chartData, pos, theme, contentY, contentH) {
2160
+ const chartType = chartData.type === "pie"
2161
+ ? "pie"
2162
+ : chartData.type === "line"
2163
+ ? "line"
2164
+ : "bar";
2165
+ const series = chartData.series || [];
2166
+ if (series.length === 0) {
2167
+ return;
2168
+ }
2169
+ const chartDataForPptx = series.map((s) => ({
2170
+ name: s.name || "Data",
2171
+ labels: s.labels || [],
2172
+ values: s.values || [],
2173
+ }));
2174
+ try {
2175
+ slide.addChart(chartType, chartDataForPptx, {
2176
+ x: pos.x + 0.1,
2177
+ y: contentY,
2178
+ w: pos.w - 0.2,
2179
+ h: contentH,
2180
+ showLegend: false,
2181
+ showTitle: false,
2182
+ chartColors: [
2183
+ theme.colors.primary.replace("#", ""),
2184
+ theme.colors.secondary.replace("#", ""),
2185
+ theme.colors.accent.replace("#", ""),
2186
+ theme.colors.muted.replace("#", ""),
2187
+ ],
2188
+ });
2189
+ }
2190
+ catch {
2191
+ // Fallback: show placeholder
2192
+ slide.addText("Chart", {
2193
+ x: pos.x,
2194
+ y: contentY,
2195
+ w: pos.w,
2196
+ h: contentH,
2197
+ fontSize: 14,
2198
+ color: theme.colors.muted.replace("#", ""),
2199
+ align: "center",
2200
+ valign: "middle",
2201
+ fit: DEFAULT_TEXT_FIT,
2202
+ });
2203
+ }
2204
+ }
2205
+ /**
2206
+ * Render a composite/dashboard slide with multiple content zones
2207
+ *
2208
+ * @example
2209
+ * // Left: bullets, Right: chart
2210
+ * renderDashboardSlide(slide, "Overview", {
2211
+ * layout: "left-right",
2212
+ * zones: [
2213
+ * { type: "bullets", title: "Key Points", data: bullets },
2214
+ * { type: "chart", title: "Trend", data: chartData }
2215
+ * ]
2216
+ * }, theme);
2217
+ */
2218
+ export function renderDashboardSlide(slide, title, content, theme) {
2219
+ addTitle(slide, title, theme, false);
2220
+ const layoutPositions = COMPOSITE_LAYOUTS[content.layout] || COMPOSITE_LAYOUTS["left-right"];
2221
+ const zones = content.zones || [];
2222
+ zones.forEach((zone, idx) => {
2223
+ if (idx >= layoutPositions.length) {
2224
+ return;
2225
+ }
2226
+ const pos = layoutPositions[idx];
2227
+ const { contentY, contentH } = renderContentBox(slide, pos, zone.title, theme, zone.isPrimary);
2228
+ switch (zone.type) {
2229
+ case "bullets":
2230
+ if (Array.isArray(zone.data)) {
2231
+ renderBulletsInZone(slide, zone.data, pos, theme, contentY, contentH);
2232
+ }
2233
+ break;
2234
+ case "stats":
2235
+ if (zone.data && typeof zone.data === "object") {
2236
+ renderStatInZone(slide, zone.data, pos, theme, contentY, contentH);
2237
+ }
2238
+ break;
2239
+ case "icon-box":
2240
+ if (zone.data && typeof zone.data === "object") {
2241
+ const iconData = zone.data;
2242
+ renderIconBoxInZone({
2243
+ slide,
2244
+ icon: iconData.icon,
2245
+ label: iconData.label,
2246
+ description: iconData.description,
2247
+ pos,
2248
+ theme,
2249
+ contentY,
2250
+ contentH,
2251
+ });
2252
+ }
2253
+ break;
2254
+ case "chart":
2255
+ if (zone.data && typeof zone.data === "object") {
2256
+ renderMiniChartInZone(slide, zone.data, pos, theme, contentY, contentH);
2257
+ }
2258
+ break;
2259
+ case "text-box":
2260
+ if (typeof zone.data === "string") {
2261
+ slide.addText(zone.data, {
2262
+ x: pos.x + 0.15,
2263
+ y: contentY,
2264
+ w: pos.w - 0.3,
2265
+ h: contentH,
2266
+ fontSize: 12,
2267
+ fontFace: theme.fonts.body,
2268
+ color: theme.colors.text.replace("#", ""),
2269
+ valign: "top",
2270
+ });
2271
+ }
2272
+ break;
2273
+ }
2274
+ });
2275
+ }
2276
+ /**
2277
+ * Render a mixed content slide with left bullets and right chart
2278
+ * Common pattern: explanation on left, visualization on right
2279
+ */
2280
+ export function renderMixedContentSlide(slide, title, content, theme) {
2281
+ addTitle(slide, title, theme, false);
2282
+ // Left side: bullets or text
2283
+ if (content.bullets && content.bullets.length > 0) {
2284
+ const leftPos = COMPOSITE_LAYOUTS["left-right"][0];
2285
+ const { contentY, contentH } = renderContentBox(slide, leftPos, content.leftColumn?.title, theme, true);
2286
+ renderBulletsInZone(slide, content.bullets, leftPos, theme, contentY, contentH);
2287
+ }
2288
+ // Right side: chart if available
2289
+ if (content.chartData) {
2290
+ const rightPos = COMPOSITE_LAYOUTS["left-right"][1];
2291
+ const { contentY, contentH } = renderContentBox(slide, rightPos, "Data", theme, false);
2292
+ renderMiniChartInZone(slide, content.chartData, rightPos, theme, contentY, contentH);
2293
+ }
2294
+ // Or statistics
2295
+ else if (content.statistics && content.statistics.length > 0) {
2296
+ const rightPos = COMPOSITE_LAYOUTS["left-right"][1];
2297
+ renderContentBox(slide, rightPos, "Metrics", theme, false);
2298
+ // Show up to 3 stats stacked
2299
+ const stats = content.statistics.slice(0, 3);
2300
+ const statHeight = rightPos.h / stats.length;
2301
+ stats.forEach((stat, idx) => {
2302
+ renderStatInZone(slide, stat, { ...rightPos, y: rightPos.y + idx * statHeight, h: statHeight }, theme, rightPos.y + idx * statHeight + 0.1, statHeight - 0.2);
2303
+ });
2304
+ }
2305
+ }
2306
+ /**
2307
+ * Render a stats grid slide with multiple stat boxes
2308
+ */
2309
+ export function renderStatsGridSlide(slide, title, content, theme) {
2310
+ addTitle(slide, title, theme, false);
2311
+ const stats = content.statistics || [];
2312
+ if (stats.length === 0) {
2313
+ return;
2314
+ }
2315
+ // Choose layout based on stat count
2316
+ let layout;
2317
+ if (stats.length <= 2) {
2318
+ layout = COMPOSITE_LAYOUTS["left-right"];
2319
+ }
2320
+ else if (stats.length <= 3) {
2321
+ layout = COMPOSITE_LAYOUTS["three-cols"];
2322
+ }
2323
+ else if (stats.length <= 4) {
2324
+ layout = COMPOSITE_LAYOUTS["quadrants"];
2325
+ }
2326
+ else if (stats.length <= 5) {
2327
+ layout = COMPOSITE_LAYOUTS["five-boxes"];
2328
+ }
2329
+ else {
2330
+ layout = COMPOSITE_LAYOUTS["six-boxes"];
2331
+ }
2332
+ stats.slice(0, layout.length).forEach((stat, idx) => {
2333
+ const pos = layout[idx];
2334
+ const isPrimary = idx === 0;
2335
+ const { contentY, contentH } = renderContentBox(slide, pos, undefined, theme, isPrimary);
2336
+ renderStatInZone(slide, stat, pos, theme, contentY, contentH);
2337
+ });
2338
+ }
2339
+ /**
2340
+ * Render an icon grid slide with multiple icon boxes
2341
+ */
2342
+ export function renderIconGridSlide(slide, title, content, theme) {
2343
+ addTitle(slide, title, theme, false);
2344
+ const icons = content.icons || content.features || [];
2345
+ if (icons.length === 0) {
2346
+ return;
2347
+ }
2348
+ // Choose layout based on icon count
2349
+ let layout;
2350
+ if (icons.length <= 2) {
2351
+ layout = COMPOSITE_LAYOUTS["left-right"];
2352
+ }
2353
+ else if (icons.length <= 3) {
2354
+ layout = COMPOSITE_LAYOUTS["three-cols"];
2355
+ }
2356
+ else if (icons.length <= 4) {
2357
+ layout = COMPOSITE_LAYOUTS["quadrants"];
2358
+ }
2359
+ else if (icons.length <= 5) {
2360
+ layout = COMPOSITE_LAYOUTS["five-boxes"];
2361
+ }
2362
+ else {
2363
+ layout = COMPOSITE_LAYOUTS["six-boxes"];
2364
+ }
2365
+ icons.slice(0, layout.length).forEach((item, idx) => {
2366
+ const pos = layout[idx];
2367
+ const isPrimary = idx === 0;
2368
+ const { contentY, contentH } = renderContentBox(slide, pos, undefined, theme, isPrimary);
2369
+ const icon = item.icon || "1F4A1";
2370
+ const label = item.title || item.label || "";
2371
+ const description = item.description;
2372
+ renderIconBoxInZone({
2373
+ slide,
2374
+ icon,
2375
+ label,
2376
+ description,
2377
+ pos,
2378
+ theme,
2379
+ contentY,
2380
+ contentH,
2381
+ });
2382
+ });
2383
+ }