@retrivora-ai/rag-engine 2.2.5 → 2.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { V as VectorDBConfig, L as LLMConfig, d as EmbeddingConfig, i as RagConfig, n as UniversalRagConfig, o as UpsertDocument, q as VectorMatch, G as GraphDBConfig, r as GraphNode, s as Edge, t as GraphSearchResult, I as ILLMProvider, p as VectorDBProvider, g as LLMProvider, e as EmbeddingProvider, R as RAGConfig, m as UIConfig, C as ChatMessage, b as ChatOptions, E as EmbedOptions } from './ILLMProvider-BWa68XX5.mjs';
2
2
  export { B as BarChartData, u as CarouselProduct, c as ChatResponse, v as IRetriever, f as IngestDocument, h as LatencyBreakdown, w as LineChartDataPoint, M as MessageRole, x as MetricCardData, O as ObservabilityTrace, P as PieChartData, y as Product, j as RagMessage, k as RetrievalConfig, z as RetrievalResult, l as RetrievedChunk, A as RetrivoraChunkMetadata, D as RetrivoraIngestedDocument, S as ScatterPlotDataPoint, F as SuggestionsResponse, H as TableData, T as TokenUsage, J as UITransformationResponse, U as UseRagChatOptions, a as UseRagChatReturn, K as VisualizationType, W as WorkflowConfig } from './ILLMProvider-BWa68XX5.mjs';
3
- import { I as IRenderRule, i as DecisionContext, k as IntentCategory, n as RenderDecision } from './index-BbJGyNmW.mjs';
4
- export { x as ArchitectureCardProps, A as AuthenticationException, y as CarouselRendererStrategy, z as ChartRendererStrategy, e as ChartType, B as ChatViewportSize, C as ChatWidgetProps, a as ChatWindowProps, f as Chunk, g as ChunkOptions, c as ClientConfig, b as ConfigProviderProps, h as ConfigurationException, F as DocumentChunker, D as DocumentUploadProps, E as EmbeddingFailedException, j as IRendererStrategy, l as IntentClassifier, M as MessageBubbleProps, G as MixedRendererStrategy, H as Pipeline, J as PipelineStep, P as ProductCardProps, d as ProductCarouselProps, m as ProviderNotFoundException, K as ProviderPill, R as RateLimitException, L as RenderSectionDecision, o as RenderType, p as RendererRegistry, q as RetrievalException, r as Retrivora, s as RetrivoraError, t as RetrivoraErrorCode, u as RuleEngine, v as SDK_VERSION, N as Snippet, S as SourceCardProps, T as TableRendererStrategy, O as TextRendererStrategy, V as VisualizationDecisionEngine, w as decideVisualization, Q as wrapError } from './index-BbJGyNmW.mjs';
3
+ import { I as IRenderRule, i as DecisionContext, k as IntentCategory, q as RenderDecision } from './LicenseValidator-B3xpJaVf.mjs';
4
+ export { F as ArchitectureCardProps, A as AuthenticationException, G as CarouselRendererStrategy, H as ChartRendererStrategy, e as ChartType, J as ChatViewportSize, C as ChatWidgetProps, a as ChatWindowProps, f as Chunk, g as ChunkOptions, c as ClientConfig, b as ConfigProviderProps, h as ConfigurationException, K as DocumentChunker, D as DocumentUploadProps, E as EmbeddingFailedException, j as IRendererStrategy, l as IntentClassifier, L as LicenseValidationError, m as LicenseValidationRequest, n as LicenseValidationResponse, o as LicenseValidator, M as MessageBubbleProps, N as MixedRendererStrategy, O as Pipeline, Q as PipelineStep, P as ProductCardProps, d as ProductCarouselProps, p as ProviderNotFoundException, T as ProviderPill, R as RateLimitException, U as RenderSectionDecision, r as RenderType, s as RendererRegistry, t as RetrievalException, u as Retrivora, v as RetrivoraError, w as RetrivoraErrorCode, x as RuleEngine, y as SDKVersionUnsupportedError, z as SDK_VERSION, W as Snippet, S as SourceCardProps, X as TableRendererStrategy, Y as TextRendererStrategy, V as VisualizationDecisionEngine, B as decideVisualization, Z as wrapError } from './LicenseValidator-B3xpJaVf.mjs';
5
5
  import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-DvbtNz7m.mjs';
6
6
  export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createFeedbackHandler, e as createHealthHandler, f as createHistoryHandler, g as createIngestHandler, h as createRagHandler, i as createSessionsHandler, j as createStreamHandler, k as createUploadHandler, s as sseErrorFrame, l as sseFrame, m as sseMetaFrame, n as sseTextFrame } from './index-DvbtNz7m.mjs';
7
7
  import 'react';
package/dist/server.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { V as VectorDBConfig, L as LLMConfig, d as EmbeddingConfig, i as RagConfig, n as UniversalRagConfig, o as UpsertDocument, q as VectorMatch, G as GraphDBConfig, r as GraphNode, s as Edge, t as GraphSearchResult, I as ILLMProvider, p as VectorDBProvider, g as LLMProvider, e as EmbeddingProvider, R as RAGConfig, m as UIConfig, C as ChatMessage, b as ChatOptions, E as EmbedOptions } from './ILLMProvider-BWa68XX5.js';
2
2
  export { B as BarChartData, u as CarouselProduct, c as ChatResponse, v as IRetriever, f as IngestDocument, h as LatencyBreakdown, w as LineChartDataPoint, M as MessageRole, x as MetricCardData, O as ObservabilityTrace, P as PieChartData, y as Product, j as RagMessage, k as RetrievalConfig, z as RetrievalResult, l as RetrievedChunk, A as RetrivoraChunkMetadata, D as RetrivoraIngestedDocument, S as ScatterPlotDataPoint, F as SuggestionsResponse, H as TableData, T as TokenUsage, J as UITransformationResponse, U as UseRagChatOptions, a as UseRagChatReturn, K as VisualizationType, W as WorkflowConfig } from './ILLMProvider-BWa68XX5.js';
3
- import { I as IRenderRule, i as DecisionContext, k as IntentCategory, n as RenderDecision } from './index-BCbeeh74.js';
4
- export { x as ArchitectureCardProps, A as AuthenticationException, y as CarouselRendererStrategy, z as ChartRendererStrategy, e as ChartType, B as ChatViewportSize, C as ChatWidgetProps, a as ChatWindowProps, f as Chunk, g as ChunkOptions, c as ClientConfig, b as ConfigProviderProps, h as ConfigurationException, F as DocumentChunker, D as DocumentUploadProps, E as EmbeddingFailedException, j as IRendererStrategy, l as IntentClassifier, M as MessageBubbleProps, G as MixedRendererStrategy, H as Pipeline, J as PipelineStep, P as ProductCardProps, d as ProductCarouselProps, m as ProviderNotFoundException, K as ProviderPill, R as RateLimitException, L as RenderSectionDecision, o as RenderType, p as RendererRegistry, q as RetrievalException, r as Retrivora, s as RetrivoraError, t as RetrivoraErrorCode, u as RuleEngine, v as SDK_VERSION, N as Snippet, S as SourceCardProps, T as TableRendererStrategy, O as TextRendererStrategy, V as VisualizationDecisionEngine, w as decideVisualization, Q as wrapError } from './index-BCbeeh74.js';
3
+ import { I as IRenderRule, i as DecisionContext, k as IntentCategory, q as RenderDecision } from './LicenseValidator-D4I4pbSL.js';
4
+ export { F as ArchitectureCardProps, A as AuthenticationException, G as CarouselRendererStrategy, H as ChartRendererStrategy, e as ChartType, J as ChatViewportSize, C as ChatWidgetProps, a as ChatWindowProps, f as Chunk, g as ChunkOptions, c as ClientConfig, b as ConfigProviderProps, h as ConfigurationException, K as DocumentChunker, D as DocumentUploadProps, E as EmbeddingFailedException, j as IRendererStrategy, l as IntentClassifier, L as LicenseValidationError, m as LicenseValidationRequest, n as LicenseValidationResponse, o as LicenseValidator, M as MessageBubbleProps, N as MixedRendererStrategy, O as Pipeline, Q as PipelineStep, P as ProductCardProps, d as ProductCarouselProps, p as ProviderNotFoundException, T as ProviderPill, R as RateLimitException, U as RenderSectionDecision, r as RenderType, s as RendererRegistry, t as RetrievalException, u as Retrivora, v as RetrivoraError, w as RetrivoraErrorCode, x as RuleEngine, y as SDKVersionUnsupportedError, z as SDK_VERSION, W as Snippet, S as SourceCardProps, X as TableRendererStrategy, Y as TextRendererStrategy, V as VisualizationDecisionEngine, B as decideVisualization, Z as wrapError } from './LicenseValidator-D4I4pbSL.js';
5
5
  import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-B5TTZWkx.js';
6
6
  export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createFeedbackHandler, e as createHealthHandler, f as createHistoryHandler, g as createIngestHandler, h as createRagHandler, i as createSessionsHandler, j as createStreamHandler, k as createUploadHandler, s as sseErrorFrame, l as sseFrame, m as sseMetaFrame, n as sseTextFrame } from './index-B5TTZWkx.js';
7
7
  import 'react';
package/dist/server.js CHANGED
@@ -2224,6 +2224,8 @@ __export(server_exports, {
2224
2224
  IntentClassifier: () => IntentClassifier,
2225
2225
  LLMFactory: () => LLMFactory,
2226
2226
  LLM_PROFILES: () => LLM_PROFILES,
2227
+ LicenseValidationError: () => LicenseValidationError,
2228
+ LicenseValidator: () => LicenseValidator,
2227
2229
  LicenseVerifier: () => LicenseVerifier,
2228
2230
  MilvusProvider: () => MilvusProvider,
2229
2231
  MixedRendererStrategy: () => MixedRendererStrategy,
@@ -2254,6 +2256,7 @@ __export(server_exports, {
2254
2256
  Rule6SmallResultSetRule: () => Rule6SmallResultSetRule,
2255
2257
  Rule7LargeTableRule: () => Rule7LargeTableRule,
2256
2258
  RuleEngine: () => RuleEngine,
2259
+ SDKVersionUnsupportedError: () => SDKVersionUnsupportedError,
2257
2260
  SDK_VERSION: () => SDK_VERSION,
2258
2261
  TableRendererStrategy: () => TableRendererStrategy,
2259
2262
  TextRendererStrategy: () => TextRendererStrategy,
@@ -2328,6 +2331,16 @@ var AuthenticationException = class extends RetrivoraError {
2328
2331
  super(message, "AUTHENTICATION_ERROR", details);
2329
2332
  }
2330
2333
  };
2334
+ var SDKVersionUnsupportedError = class extends RetrivoraError {
2335
+ constructor(message = "This SDK version is no longer supported.", details) {
2336
+ super(message, "SDK_VERSION_UNSUPPORTED", details);
2337
+ }
2338
+ };
2339
+ var LicenseValidationError = class extends RetrivoraError {
2340
+ constructor(message = "License validation failed.", details) {
2341
+ super(message, "LICENSE_VALIDATION_ERROR", details);
2342
+ }
2343
+ };
2331
2344
  function wrapError(err, defaultCode, defaultMessage) {
2332
2345
  var _a2;
2333
2346
  if (err instanceof RetrivoraError) {
@@ -2340,8 +2353,10 @@ function wrapError(err, defaultCode, defaultMessage) {
2340
2353
  if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
2341
2354
  return new RateLimitException(message, err);
2342
2355
  }
2343
- if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
2344
- return new AuthenticationException(message, err);
2356
+ if (status === 401 || status === 403 || /unauthorized|auth|license|revoked|terminated|api[- ]?key/i.test(message) || code === "INVALID_API_KEY" || code === "LICENSE_DELETED" || code === "LICENSE_INACTIVE") {
2357
+ const isLicenseError = /403|license|revoked|terminated/i.test(message) || status === 403;
2358
+ const cleanMsg = isLicenseError ? "Your Retrivora license key has been terminated, suspended, or revoked. Access denied." : message;
2359
+ return new AuthenticationException(cleanMsg, err);
2345
2360
  }
2346
2361
  switch (defaultCode) {
2347
2362
  case "PROVIDER_NOT_FOUND":
@@ -4808,7 +4823,7 @@ var ConfigValidator = class {
4808
4823
  // package.json
4809
4824
  var package_default = {
4810
4825
  name: "@retrivora-ai/rag-engine",
4811
- version: "2.2.5",
4826
+ version: "2.2.7",
4812
4827
  description: "Retrivora AI is a plug-and-play AI engine for RAG chat experiences \u2014 generic vector DB + LLM provider, embeddable or standalone.",
4813
4828
  author: "Abhinav Alkuchi",
4814
4829
  license: "UNLICENSED",
@@ -10924,7 +10939,10 @@ function createStreamHandler(configOrPlugin, options) {
10924
10939
  }
10925
10940
  } catch (streamError) {
10926
10941
  if (isActive) {
10927
- const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
10942
+ let errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
10943
+ if (errorMessage.includes("403") || errorMessage.toLowerCase().includes("license") || errorMessage.toLowerCase().includes("revoked") || errorMessage.toLowerCase().includes("terminated")) {
10944
+ errorMessage = "Your Retrivora license key has been terminated, suspended, or revoked. Access denied.";
10945
+ }
10928
10946
  console.error("[createStreamHandler] Stream error:", streamError);
10929
10947
  reportTelemetry(req, plugin, "QUERY_GENERATION", "error", errorMessage);
10930
10948
  try {
@@ -11325,6 +11343,108 @@ function createRagHandler(configOrPlugin, options) {
11325
11343
  }
11326
11344
  };
11327
11345
  }
11346
+
11347
+ // src/core/LicenseValidator.ts
11348
+ var _LicenseValidator = class _LicenseValidator {
11349
+ // 5-minute TTL for successful validation only
11350
+ constructor() {
11351
+ this.cache = /* @__PURE__ */ new Map();
11352
+ }
11353
+ static getInstance() {
11354
+ if (!_LicenseValidator.instance) {
11355
+ _LicenseValidator.instance = new _LicenseValidator();
11356
+ }
11357
+ return _LicenseValidator.instance;
11358
+ }
11359
+ /**
11360
+ * Invalidate local validation cache for a license key
11361
+ */
11362
+ purgeCache(licenseKey) {
11363
+ if (licenseKey) {
11364
+ this.cache.delete(licenseKey);
11365
+ } else {
11366
+ this.cache.clear();
11367
+ }
11368
+ }
11369
+ /**
11370
+ * Validate license status and SDK version against Retrivora License Service
11371
+ */
11372
+ async validate(request) {
11373
+ const {
11374
+ licenseKey,
11375
+ projectId,
11376
+ sdkVersion = SDK_VERSION,
11377
+ sdk = "@retrivora-ai/rag-engine",
11378
+ platform = typeof window !== "undefined" ? "browser" : "node",
11379
+ retrivoraApiBase,
11380
+ headers: customHeaders
11381
+ } = request;
11382
+ if (!licenseKey) {
11383
+ this.purgeCache(licenseKey);
11384
+ throw new LicenseValidationError("Missing RETRIVORA_LICENSE_KEY in request.");
11385
+ }
11386
+ const cached = this.cache.get(licenseKey);
11387
+ if (cached) {
11388
+ const isFresh = Date.now() - cached.timestamp < _LicenseValidator.SUCCESS_CACHE_TTL_MS;
11389
+ if (isFresh && cached.response.valid && cached.response.licenseStatus === "ACTIVE" && !cached.response.forceUpgrade) {
11390
+ return cached.response;
11391
+ } else {
11392
+ this.cache.delete(licenseKey);
11393
+ }
11394
+ }
11395
+ const base = retrivoraApiBase || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_RETRIVORA_API_BASE || process.env.RETRIVORA_API_BASE : "") || "/api/retrivora";
11396
+ const validateUrl = `${base.replace(/\/$/, "")}/v1/license/validate`;
11397
+ let res;
11398
+ try {
11399
+ res = await fetch(validateUrl, {
11400
+ method: "POST",
11401
+ cache: "no-store",
11402
+ headers: __spreadValues({
11403
+ "Content-Type": "application/json",
11404
+ "x-license-key": licenseKey,
11405
+ "x-sdk-version": sdkVersion
11406
+ }, customHeaders || {}),
11407
+ body: JSON.stringify({
11408
+ licenseKey,
11409
+ projectId,
11410
+ sdkVersion,
11411
+ sdk,
11412
+ platform
11413
+ })
11414
+ });
11415
+ } catch (err) {
11416
+ this.purgeCache(licenseKey);
11417
+ throw new LicenseValidationError(`License validation request failed: ${(err == null ? void 0 : err.message) || "Network error"}`);
11418
+ }
11419
+ const data = await res.json().catch(() => ({
11420
+ valid: false,
11421
+ licenseStatus: "REVOKED",
11422
+ minimumSupportedVersion: "2.1.0",
11423
+ latestVersion: SDK_VERSION,
11424
+ forceUpgrade: false,
11425
+ expiresAt: null,
11426
+ message: "Failed to parse license validation response."
11427
+ }));
11428
+ if (!res.ok || !data.valid || data.licenseStatus !== "ACTIVE" || data.forceUpgrade) {
11429
+ this.purgeCache(licenseKey);
11430
+ if (data.forceUpgrade || res.status === 426) {
11431
+ throw new SDKVersionUnsupportedError(
11432
+ data.message || `This SDK version (${sdkVersion}) is no longer supported. Upgrade to version ${data.latestVersion || "2.2.6"} or later.`,
11433
+ data
11434
+ );
11435
+ }
11436
+ const errMsg = data.message || `License validation failed with status: ${data.licenseStatus}. Access denied.`;
11437
+ throw new LicenseValidationError(errMsg, data);
11438
+ }
11439
+ this.cache.set(licenseKey, {
11440
+ response: data,
11441
+ timestamp: Date.now()
11442
+ });
11443
+ return data;
11444
+ }
11445
+ };
11446
+ _LicenseValidator.SUCCESS_CACHE_TTL_MS = 5 * 60 * 1e3;
11447
+ var LicenseValidator = _LicenseValidator;
11328
11448
  // Annotate the CommonJS export names for ESM import in node:
11329
11449
  0 && (module.exports = {
11330
11450
  AnthropicProvider,
@@ -11347,6 +11467,8 @@ function createRagHandler(configOrPlugin, options) {
11347
11467
  IntentClassifier,
11348
11468
  LLMFactory,
11349
11469
  LLM_PROFILES,
11470
+ LicenseValidationError,
11471
+ LicenseValidator,
11350
11472
  LicenseVerifier,
11351
11473
  MilvusProvider,
11352
11474
  MixedRendererStrategy,
@@ -11377,6 +11499,7 @@ function createRagHandler(configOrPlugin, options) {
11377
11499
  Rule6SmallResultSetRule,
11378
11500
  Rule7LargeTableRule,
11379
11501
  RuleEngine,
11502
+ SDKVersionUnsupportedError,
11380
11503
  SDK_VERSION,
11381
11504
  TableRendererStrategy,
11382
11505
  TextRendererStrategy,
package/dist/server.mjs CHANGED
@@ -2231,6 +2231,16 @@ var AuthenticationException = class extends RetrivoraError {
2231
2231
  super(message, "AUTHENTICATION_ERROR", details);
2232
2232
  }
2233
2233
  };
2234
+ var SDKVersionUnsupportedError = class extends RetrivoraError {
2235
+ constructor(message = "This SDK version is no longer supported.", details) {
2236
+ super(message, "SDK_VERSION_UNSUPPORTED", details);
2237
+ }
2238
+ };
2239
+ var LicenseValidationError = class extends RetrivoraError {
2240
+ constructor(message = "License validation failed.", details) {
2241
+ super(message, "LICENSE_VALIDATION_ERROR", details);
2242
+ }
2243
+ };
2234
2244
  function wrapError(err, defaultCode, defaultMessage) {
2235
2245
  var _a2;
2236
2246
  if (err instanceof RetrivoraError) {
@@ -2243,8 +2253,10 @@ function wrapError(err, defaultCode, defaultMessage) {
2243
2253
  if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
2244
2254
  return new RateLimitException(message, err);
2245
2255
  }
2246
- if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
2247
- return new AuthenticationException(message, err);
2256
+ if (status === 401 || status === 403 || /unauthorized|auth|license|revoked|terminated|api[- ]?key/i.test(message) || code === "INVALID_API_KEY" || code === "LICENSE_DELETED" || code === "LICENSE_INACTIVE") {
2257
+ const isLicenseError = /403|license|revoked|terminated/i.test(message) || status === 403;
2258
+ const cleanMsg = isLicenseError ? "Your Retrivora license key has been terminated, suspended, or revoked. Access denied." : message;
2259
+ return new AuthenticationException(cleanMsg, err);
2248
2260
  }
2249
2261
  switch (defaultCode) {
2250
2262
  case "PROVIDER_NOT_FOUND":
@@ -4711,7 +4723,7 @@ var ConfigValidator = class {
4711
4723
  // package.json
4712
4724
  var package_default = {
4713
4725
  name: "@retrivora-ai/rag-engine",
4714
- version: "2.2.5",
4726
+ version: "2.2.7",
4715
4727
  description: "Retrivora AI is a plug-and-play AI engine for RAG chat experiences \u2014 generic vector DB + LLM provider, embeddable or standalone.",
4716
4728
  author: "Abhinav Alkuchi",
4717
4729
  license: "UNLICENSED",
@@ -10827,7 +10839,10 @@ function createStreamHandler(configOrPlugin, options) {
10827
10839
  }
10828
10840
  } catch (streamError) {
10829
10841
  if (isActive) {
10830
- const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
10842
+ let errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
10843
+ if (errorMessage.includes("403") || errorMessage.toLowerCase().includes("license") || errorMessage.toLowerCase().includes("revoked") || errorMessage.toLowerCase().includes("terminated")) {
10844
+ errorMessage = "Your Retrivora license key has been terminated, suspended, or revoked. Access denied.";
10845
+ }
10831
10846
  console.error("[createStreamHandler] Stream error:", streamError);
10832
10847
  reportTelemetry(req, plugin, "QUERY_GENERATION", "error", errorMessage);
10833
10848
  try {
@@ -11228,6 +11243,108 @@ function createRagHandler(configOrPlugin, options) {
11228
11243
  }
11229
11244
  };
11230
11245
  }
11246
+
11247
+ // src/core/LicenseValidator.ts
11248
+ var _LicenseValidator = class _LicenseValidator {
11249
+ // 5-minute TTL for successful validation only
11250
+ constructor() {
11251
+ this.cache = /* @__PURE__ */ new Map();
11252
+ }
11253
+ static getInstance() {
11254
+ if (!_LicenseValidator.instance) {
11255
+ _LicenseValidator.instance = new _LicenseValidator();
11256
+ }
11257
+ return _LicenseValidator.instance;
11258
+ }
11259
+ /**
11260
+ * Invalidate local validation cache for a license key
11261
+ */
11262
+ purgeCache(licenseKey) {
11263
+ if (licenseKey) {
11264
+ this.cache.delete(licenseKey);
11265
+ } else {
11266
+ this.cache.clear();
11267
+ }
11268
+ }
11269
+ /**
11270
+ * Validate license status and SDK version against Retrivora License Service
11271
+ */
11272
+ async validate(request) {
11273
+ const {
11274
+ licenseKey,
11275
+ projectId,
11276
+ sdkVersion = SDK_VERSION,
11277
+ sdk = "@retrivora-ai/rag-engine",
11278
+ platform = typeof window !== "undefined" ? "browser" : "node",
11279
+ retrivoraApiBase,
11280
+ headers: customHeaders
11281
+ } = request;
11282
+ if (!licenseKey) {
11283
+ this.purgeCache(licenseKey);
11284
+ throw new LicenseValidationError("Missing RETRIVORA_LICENSE_KEY in request.");
11285
+ }
11286
+ const cached = this.cache.get(licenseKey);
11287
+ if (cached) {
11288
+ const isFresh = Date.now() - cached.timestamp < _LicenseValidator.SUCCESS_CACHE_TTL_MS;
11289
+ if (isFresh && cached.response.valid && cached.response.licenseStatus === "ACTIVE" && !cached.response.forceUpgrade) {
11290
+ return cached.response;
11291
+ } else {
11292
+ this.cache.delete(licenseKey);
11293
+ }
11294
+ }
11295
+ const base = retrivoraApiBase || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_RETRIVORA_API_BASE || process.env.RETRIVORA_API_BASE : "") || "/api/retrivora";
11296
+ const validateUrl = `${base.replace(/\/$/, "")}/v1/license/validate`;
11297
+ let res;
11298
+ try {
11299
+ res = await fetch(validateUrl, {
11300
+ method: "POST",
11301
+ cache: "no-store",
11302
+ headers: __spreadValues({
11303
+ "Content-Type": "application/json",
11304
+ "x-license-key": licenseKey,
11305
+ "x-sdk-version": sdkVersion
11306
+ }, customHeaders || {}),
11307
+ body: JSON.stringify({
11308
+ licenseKey,
11309
+ projectId,
11310
+ sdkVersion,
11311
+ sdk,
11312
+ platform
11313
+ })
11314
+ });
11315
+ } catch (err) {
11316
+ this.purgeCache(licenseKey);
11317
+ throw new LicenseValidationError(`License validation request failed: ${(err == null ? void 0 : err.message) || "Network error"}`);
11318
+ }
11319
+ const data = await res.json().catch(() => ({
11320
+ valid: false,
11321
+ licenseStatus: "REVOKED",
11322
+ minimumSupportedVersion: "2.1.0",
11323
+ latestVersion: SDK_VERSION,
11324
+ forceUpgrade: false,
11325
+ expiresAt: null,
11326
+ message: "Failed to parse license validation response."
11327
+ }));
11328
+ if (!res.ok || !data.valid || data.licenseStatus !== "ACTIVE" || data.forceUpgrade) {
11329
+ this.purgeCache(licenseKey);
11330
+ if (data.forceUpgrade || res.status === 426) {
11331
+ throw new SDKVersionUnsupportedError(
11332
+ data.message || `This SDK version (${sdkVersion}) is no longer supported. Upgrade to version ${data.latestVersion || "2.2.6"} or later.`,
11333
+ data
11334
+ );
11335
+ }
11336
+ const errMsg = data.message || `License validation failed with status: ${data.licenseStatus}. Access denied.`;
11337
+ throw new LicenseValidationError(errMsg, data);
11338
+ }
11339
+ this.cache.set(licenseKey, {
11340
+ response: data,
11341
+ timestamp: Date.now()
11342
+ });
11343
+ return data;
11344
+ }
11345
+ };
11346
+ _LicenseValidator.SUCCESS_CACHE_TTL_MS = 5 * 60 * 1e3;
11347
+ var LicenseValidator = _LicenseValidator;
11231
11348
  export {
11232
11349
  AnthropicProvider,
11233
11350
  AuthenticationException,
@@ -11249,6 +11366,8 @@ export {
11249
11366
  IntentClassifier,
11250
11367
  LLMFactory,
11251
11368
  LLM_PROFILES,
11369
+ LicenseValidationError,
11370
+ LicenseValidator,
11252
11371
  LicenseVerifier,
11253
11372
  MilvusProvider,
11254
11373
  MixedRendererStrategy,
@@ -11279,6 +11398,7 @@ export {
11279
11398
  Rule6SmallResultSetRule,
11280
11399
  Rule7LargeTableRule,
11281
11400
  RuleEngine,
11401
+ SDKVersionUnsupportedError,
11282
11402
  SDK_VERSION,
11283
11403
  TableRendererStrategy,
11284
11404
  TextRendererStrategy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "2.2.5",
3
+ "version": "2.2.7",
4
4
  "description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
5
5
  "author": "Abhinav Alkuchi",
6
6
  "license": "UNLICENSED",
@@ -1,10 +1,10 @@
1
- 'use client';
2
-
3
1
  import React, { useState } from 'react';
4
- import { MessageSquare, X } from 'lucide-react';
2
+ import { MessageSquare, X, AlertTriangle } from 'lucide-react';
5
3
  import { ChatWindow } from './ChatWindow';
6
4
  import { useConfig } from './ConfigProvider';
7
5
  import { ChatWidgetProps } from '../types';
6
+ import { SDK_VERSION } from '../version';
7
+ import { LicenseValidator } from '../core/LicenseValidator';
8
8
 
9
9
  const DEFAULT_DIMENSIONS = { width: 380, height: 600 };
10
10
 
@@ -47,13 +47,15 @@ const GEMINI_STYLES = `
47
47
  `;
48
48
 
49
49
  export function ChatWidget({ position = 'bottom-right', onAddToCart, apiUrl, retrivoraApiBase, headers }: ChatWidgetProps) {
50
- const { ui } = useConfig();
50
+ const { ui, projectId } = useConfig();
51
51
  const [isOpen, setIsOpen] = useState(false);
52
52
  const [hasUnread, setHasUnread] = useState(false);
53
53
  const [dimensions, setDimensions] = useState(DEFAULT_DIMENSIONS);
54
54
  const [isResizing, setIsResizing] = useState(false);
55
55
  const [isMaximized, setIsMaximized] = useState(false);
56
56
  const [prevDimensions, setPrevDimensions] = useState(DEFAULT_DIMENSIONS);
57
+ const [widgetError, setWidgetError] = useState<string | null>(null);
58
+ const [isValidating, setIsValidating] = useState(false);
57
59
 
58
60
  if (ui.showWidget === false) return null;
59
61
 
@@ -67,9 +69,26 @@ export function ChatWidget({ position = 'bottom-right', onAddToCart, apiUrl, ret
67
69
  ? 'bottom-20 left-6'
68
70
  : 'bottom-20 right-6';
69
71
 
70
- const handleOpen = () => {
71
- setIsOpen(true);
72
- setHasUnread(false);
72
+ const handleOpen = async () => {
73
+ setIsValidating(true);
74
+ try {
75
+ const licenseKey = headers?.['x-license-key'] || headers?.['authorization']?.replace(/^Bearer\s+/i, '') || '';
76
+ await LicenseValidator.getInstance().validate({
77
+ licenseKey,
78
+ projectId,
79
+ retrivoraApiBase,
80
+ headers,
81
+ });
82
+
83
+ setWidgetError(null);
84
+ setIsOpen(true);
85
+ setHasUnread(false);
86
+ } catch (err: any) {
87
+ setWidgetError(err?.message || 'Access denied.');
88
+ setIsOpen(false); // DO NOT OPEN CHAT WIDGET
89
+ } finally {
90
+ setIsValidating(false);
91
+ }
73
92
  };
74
93
 
75
94
  const handleResizeStart = (e: React.MouseEvent) => {
@@ -157,6 +176,33 @@ export function ChatWidget({ position = 'bottom-right', onAddToCart, apiUrl, ret
157
176
  />
158
177
  </div>
159
178
 
179
+ {/* ── Widget Error Toast/Pop-over (when opening is blocked) ── */}
180
+ {widgetError && !isOpen && (
181
+ <div
182
+ className={`fixed z-[9999] max-w-sm p-4 rounded-2xl shadow-2xl border border-rose-200 dark:border-rose-900/60 bg-white/95 dark:bg-[#0f0f1a]/95 backdrop-blur-xl transition-all duration-300 animate-in fade-in slide-in-from-bottom-3 ${
183
+ position === 'bottom-left' ? 'bottom-24 left-6' : 'bottom-24 right-6'
184
+ }`}
185
+ >
186
+ <div className="flex items-start gap-3">
187
+ <div className="w-8 h-8 rounded-xl bg-rose-100 dark:bg-rose-900/40 text-rose-600 dark:text-rose-400 flex items-center justify-center shrink-0 mt-0.5">
188
+ <AlertTriangle className="w-4 h-4" />
189
+ </div>
190
+ <div className="flex-1 space-y-1">
191
+ <h5 className="text-xs font-bold text-slate-900 dark:text-white">Access Blocked</h5>
192
+ <p className="text-[11px] text-slate-600 dark:text-slate-300 leading-relaxed font-medium">
193
+ {widgetError}
194
+ </p>
195
+ </div>
196
+ <button
197
+ onClick={() => setWidgetError(null)}
198
+ className="text-slate-400 hover:text-slate-600 dark:hover:text-white transition-colors p-1"
199
+ >
200
+ <X className="w-3.5 h-3.5" />
201
+ </button>
202
+ </div>
203
+ </div>
204
+ )}
205
+
160
206
  {/* ── Floating Action Button ── */}
161
207
  <button
162
208
  onClick={isOpen ? () => setIsOpen(false) : handleOpen}
@@ -7,6 +7,7 @@ import {
7
7
  X,
8
8
  Sparkles,
9
9
  ArrowUp,
10
+ ArrowUpCircle,
10
11
  TriangleAlert,
11
12
  RotateCcw,
12
13
  Maximize2,
@@ -21,6 +22,8 @@ import { useConfig } from './ConfigProvider';
21
22
  import { useRagChat } from '../hooks/useRagChat';
22
23
  import { BORDER_RADIUS_MAP, CHAT_SUGGESTIONS } from '../config/uiConstants';
23
24
  import { ChatWindowProps } from '../types';
25
+ import { SDK_VERSION } from '../version';
26
+ import { LicenseValidator } from '../core/LicenseValidator';
24
27
 
25
28
  interface SpeechRecognitionEvent {
26
29
  resultIndex: number;
@@ -86,8 +89,42 @@ export function ChatWindow({
86
89
 
87
90
  const [isListening, setIsListening] = useState(false);
88
91
  const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
92
+ const [licenseError, setLicenseError] = useState<string | null>(null);
93
+ const [versionError, setVersionError] = useState<string | null>(null);
89
94
  const recognitionRef = useRef<ISpeechRecognition | null>(null);
90
95
 
96
+ // Validate server license and SDK version on ChatWindow session initialization
97
+ useEffect(() => {
98
+ let isMounted = true;
99
+ async function validateSessionLicense() {
100
+ try {
101
+ const licenseKey = headers?.['x-license-key'] || headers?.['authorization']?.replace(/^Bearer\s+/i, '') || '';
102
+ await LicenseValidator.getInstance().validate({
103
+ licenseKey,
104
+ projectId,
105
+ retrivoraApiBase,
106
+ headers,
107
+ });
108
+
109
+ if (isMounted) {
110
+ setLicenseError(null);
111
+ setVersionError(null);
112
+ }
113
+ } catch (err: any) {
114
+ if (isMounted) {
115
+ if (err?.code === 'SDK_VERSION_UNSUPPORTED') {
116
+ setVersionError(err?.message || 'SDK version unsupported.');
117
+ } else {
118
+ setLicenseError(err?.message || 'License validation failed.');
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ validateSessionLicense();
125
+ return () => { isMounted = false; };
126
+ }, [retrivoraApiBase, headers, projectId]);
127
+
91
128
  // Initialize SpeechRecognition
92
129
  useEffect(() => {
93
130
  if (typeof window !== 'undefined') {
@@ -345,7 +382,36 @@ export function ChatWindow({
345
382
  </div>
346
383
 
347
384
  <div className="flex-1 overflow-y-auto px-4 py-4 space-y-5 scrollbar-thin scrollbar-thumb-slate-200 dark:scrollbar-thumb-white/10 scrollbar-track-transparent min-h-0 bg-slate-50 dark:bg-transparent">
348
- {!mounted || isEmpty ? (
385
+ {versionError ? (
386
+ <div className="h-full flex flex-col items-center justify-center text-center p-6 space-y-4 bg-amber-50/70 dark:bg-amber-950/20 rounded-2xl border border-amber-200/80 dark:border-amber-800/40 my-auto">
387
+ <div className="w-14 h-14 rounded-2xl bg-amber-100 dark:bg-amber-900/40 text-amber-600 dark:text-amber-400 flex items-center justify-center shadow-sm shrink-0">
388
+ <ArrowUpCircle className="w-7 h-7 animate-bounce" />
389
+ </div>
390
+ <div className="space-y-2 max-w-xs">
391
+ <h4 className="text-base font-extrabold text-slate-900 dark:text-white tracking-tight">Package Update Required</h4>
392
+ <p className="text-xs text-slate-600 dark:text-slate-300 leading-relaxed font-medium">
393
+ {versionError}
394
+ </p>
395
+ <div className="pt-2">
396
+ <code className="block bg-slate-900 text-amber-300 text-[10px] font-mono py-2 px-3 rounded-xl select-all border border-slate-800">
397
+ npm i @retrivora-ai/rag-engine@latest
398
+ </code>
399
+ </div>
400
+ </div>
401
+ </div>
402
+ ) : licenseError ? (
403
+ <div className="h-full flex flex-col items-center justify-center text-center p-6 space-y-4 bg-rose-50/50 dark:bg-rose-950/20 rounded-2xl border border-rose-200/60 dark:border-rose-800/40 my-auto">
404
+ <div className="w-14 h-14 rounded-2xl bg-rose-100 dark:bg-rose-900/40 text-rose-600 dark:text-rose-400 flex items-center justify-center shadow-sm shrink-0">
405
+ <TriangleAlert className="w-7 h-7" />
406
+ </div>
407
+ <div className="space-y-2 max-w-xs">
408
+ <h4 className="text-base font-extrabold text-slate-900 dark:text-white tracking-tight">License Invalid</h4>
409
+ <p className="text-xs text-slate-600 dark:text-slate-300 leading-relaxed font-medium">
410
+ {licenseError}
411
+ </p>
412
+ </div>
413
+ </div>
414
+ ) : !mounted || isEmpty ? (
349
415
  /* Welcome state */
350
416
  <div className="h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-4">
351
417
  <div
@@ -408,7 +474,7 @@ export function ChatWindow({
408
474
  )}
409
475
 
410
476
  {/* Error */}
411
- {error && (
477
+ {error && !licenseError && (
412
478
  <div className="flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3">
413
479
  <TriangleAlert className="w-4 h-4 flex-shrink-0" />
414
480
  <span>{error}</span>
@@ -479,7 +545,7 @@ export function ChatWindow({
479
545
  onKeyDown={handleKeyDown}
480
546
  placeholder={ui.placeholder}
481
547
  rows={1}
482
- disabled={isLoading}
548
+ disabled={isLoading || !!licenseError || !!versionError}
483
549
  className="flex-1 bg-transparent text-slate-900 dark:text-white/90 placeholder-slate-400 dark:placeholder-white/30 text-sm resize-none outline-none py-1.5 px-2 max-h-32 leading-relaxed disabled:opacity-50"
484
550
  style={{ scrollbarWidth: 'none' }}
485
551
  />
@@ -488,7 +554,7 @@ export function ChatWindow({
488
554
  <button
489
555
  type="button"
490
556
  onClick={toggleListening}
491
- disabled={isLoading}
557
+ disabled={isLoading || !!licenseError || !!versionError}
492
558
  className={`flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 disabled:active:scale-100 ${isListening
493
559
  ? 'bg-rose-500 text-white animate-pulse shadow-md shadow-rose-500/20'
494
560
  : 'text-slate-400 dark:text-white/40 hover:bg-slate-200 dark:hover:bg-white/10'
@@ -503,7 +569,8 @@ export function ChatWindow({
503
569
  <button
504
570
  type="button"
505
571
  onClick={() => setIsUploadModalOpen(true)}
506
- className="flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 text-slate-400 dark:text-white/40 hover:bg-slate-200 dark:hover:bg-white/10"
572
+ disabled={isLoading || !!licenseError || !!versionError}
573
+ className="flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 text-slate-400 dark:text-white/40 hover:bg-slate-200 dark:hover:bg-white/10 disabled:opacity-50 disabled:cursor-not-allowed"
507
574
  title="Upload Document"
508
575
  >
509
576
  <Paperclip className="w-4 h-4" />
@@ -521,14 +588,10 @@ export function ChatWindow({
521
588
  ) : (
522
589
  <button
523
590
  onClick={sendMessage}
524
- disabled={!input.trim()}
525
- className="flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all disabled:opacity-30 disabled:cursor-not-allowed hover:scale-105 active:scale-95 shadow-md"
526
- style={{
527
- background:
528
- input.trim()
529
- ? `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})`
530
- : 'rgba(148, 163, 184, 0.2)', // slate-400/20 for light mode disabled
531
- }}
591
+ disabled={!input.trim() || !!licenseError || !!versionError}
592
+ className={`flex-shrink-0 w-9 h-9 flex items-center justify-center transition-all shadow-md active:scale-95 cursor-pointer disabled:opacity-30 disabled:cursor-not-allowed disabled:active:scale-100 ${ui.borderRadius === 'full' ? 'rounded-full' : 'rounded-xl'}`}
593
+ style={{ background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }}
594
+ title="Send message"
532
595
  >
533
596
  <ArrowUp className="w-4 h-4 text-white" />
534
597
  </button>