@retrivora-ai/rag-engine 2.2.7 → 2.2.8
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/{ILLMProvider-BWa68XX5.d.mts → ILLMProvider-teTNQ1lh.d.mts} +2 -0
- package/dist/{ILLMProvider-BWa68XX5.d.ts → ILLMProvider-teTNQ1lh.d.ts} +2 -0
- package/dist/{LicenseValidator-D4I4pbSL.d.ts → LicenseValidator-CENvo9o2.d.mts} +6 -3
- package/dist/{LicenseValidator-B3xpJaVf.d.mts → LicenseValidator-CsjJp2PP.d.ts} +6 -3
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +48 -1
- package/dist/handlers/index.mjs +47 -1
- package/dist/{index-B5TTZWkx.d.ts → index-BPJ3KDYI.d.ts} +6 -2
- package/dist/{index-DvbtNz7m.d.mts → index-Dmq5lH0j.d.mts} +6 -2
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +298 -21
- package/dist/index.mjs +304 -21
- package/dist/server.d.mts +6 -6
- package/dist/server.d.ts +6 -6
- package/dist/server.js +96 -9
- package/dist/server.mjs +96 -9
- package/package.json +1 -1
- package/src/components/ChatWidget.tsx +21 -3
- package/src/components/ChatWindow.tsx +21 -2
- package/src/core/LicenseValidator.ts +62 -10
- package/src/handlers/index.ts +65 -2
- package/src/hooks/useRagChat.ts +20 -1
- package/src/types/chat.ts +2 -0
- package/src/types/props.ts +5 -2
package/dist/server.js
CHANGED
|
@@ -4823,7 +4823,7 @@ var ConfigValidator = class {
|
|
|
4823
4823
|
// package.json
|
|
4824
4824
|
var package_default = {
|
|
4825
4825
|
name: "@retrivora-ai/rag-engine",
|
|
4826
|
-
version: "2.2.
|
|
4826
|
+
version: "2.2.8",
|
|
4827
4827
|
description: "Retrivora AI is a plug-and-play AI engine for RAG chat experiences \u2014 generic vector DB + LLM provider, embeddable or standalone.",
|
|
4828
4828
|
author: "Abhinav Alkuchi",
|
|
4829
4829
|
license: "UNLICENSED",
|
|
@@ -11012,6 +11012,46 @@ function createHealthHandler(configOrPlugin, options) {
|
|
|
11012
11012
|
}
|
|
11013
11013
|
};
|
|
11014
11014
|
}
|
|
11015
|
+
function createLicenseHandler(configOrPlugin, options) {
|
|
11016
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
11017
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
11018
|
+
return async function POST(req) {
|
|
11019
|
+
var _a2;
|
|
11020
|
+
if (req) {
|
|
11021
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
11022
|
+
if (authResult) return authResult;
|
|
11023
|
+
}
|
|
11024
|
+
try {
|
|
11025
|
+
const body = await req.json().catch(() => ({}));
|
|
11026
|
+
const config = plugin.getConfig();
|
|
11027
|
+
const licenseKey = req.headers.get("x-license-key") || (body == null ? void 0 : body.licenseKey) || ((_a2 = req.headers.get("authorization")) == null ? void 0 : _a2.replace(/^Bearer\s+/i, "")) || config.licenseKey || process.env.RETRIVORA_LICENSE_KEY || process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY || "";
|
|
11028
|
+
const projectId = (body == null ? void 0 : body.projectId) || config.projectId || "my-rag-app";
|
|
11029
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId);
|
|
11030
|
+
return import_server.NextResponse.json({
|
|
11031
|
+
valid: true,
|
|
11032
|
+
licenseStatus: "ACTIVE",
|
|
11033
|
+
minimumSupportedVersion: "2.1.0",
|
|
11034
|
+
latestVersion: SDK_VERSION,
|
|
11035
|
+
forceUpgrade: false,
|
|
11036
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1e3).toISOString() : null,
|
|
11037
|
+
message: "License key is active and valid."
|
|
11038
|
+
});
|
|
11039
|
+
} catch (err) {
|
|
11040
|
+
return import_server.NextResponse.json(
|
|
11041
|
+
{
|
|
11042
|
+
valid: false,
|
|
11043
|
+
licenseStatus: "REVOKED",
|
|
11044
|
+
minimumSupportedVersion: "2.1.0",
|
|
11045
|
+
latestVersion: SDK_VERSION,
|
|
11046
|
+
forceUpgrade: false,
|
|
11047
|
+
expiresAt: null,
|
|
11048
|
+
message: (err == null ? void 0 : err.message) || "License validation failed."
|
|
11049
|
+
},
|
|
11050
|
+
{ status: 400 }
|
|
11051
|
+
);
|
|
11052
|
+
}
|
|
11053
|
+
};
|
|
11054
|
+
}
|
|
11015
11055
|
function createUploadHandler(configOrPlugin, options) {
|
|
11016
11056
|
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
11017
11057
|
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
@@ -11263,6 +11303,7 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
11263
11303
|
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
11264
11304
|
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
11265
11305
|
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
11306
|
+
const licenseHandler = createLicenseHandler(plugin, { onAuthorize });
|
|
11266
11307
|
async function routePostRequest(req, segment) {
|
|
11267
11308
|
switch (segment) {
|
|
11268
11309
|
case "chat":
|
|
@@ -11280,6 +11321,9 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
11280
11321
|
return historyHandler(req);
|
|
11281
11322
|
case "feedback":
|
|
11282
11323
|
return feedbackHandler(req);
|
|
11324
|
+
case "license/validate":
|
|
11325
|
+
case "v1/license/validate":
|
|
11326
|
+
return licenseHandler(req);
|
|
11283
11327
|
default:
|
|
11284
11328
|
return import_server.NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
11285
11329
|
}
|
|
@@ -11309,6 +11353,7 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
11309
11353
|
try {
|
|
11310
11354
|
const url = new URL(req.url);
|
|
11311
11355
|
const pathname = url.pathname;
|
|
11356
|
+
if (pathname.includes("/license/validate")) return "v1/license/validate";
|
|
11312
11357
|
if (pathname.endsWith("/upload")) return "upload";
|
|
11313
11358
|
if (pathname.endsWith("/chat") || pathname.endsWith("/chat-sync")) return "chat";
|
|
11314
11359
|
if (pathname.endsWith("/health")) return "health";
|
|
@@ -11370,6 +11415,7 @@ var _LicenseValidator = class _LicenseValidator {
|
|
|
11370
11415
|
* Validate license status and SDK version against Retrivora License Service
|
|
11371
11416
|
*/
|
|
11372
11417
|
async validate(request) {
|
|
11418
|
+
var _a2;
|
|
11373
11419
|
const {
|
|
11374
11420
|
licenseKey,
|
|
11375
11421
|
projectId,
|
|
@@ -11379,29 +11425,38 @@ var _LicenseValidator = class _LicenseValidator {
|
|
|
11379
11425
|
retrivoraApiBase,
|
|
11380
11426
|
headers: customHeaders
|
|
11381
11427
|
} = request;
|
|
11382
|
-
|
|
11383
|
-
|
|
11428
|
+
const getHeader = (name) => {
|
|
11429
|
+
if (!customHeaders) return void 0;
|
|
11430
|
+
const target = name.toLowerCase();
|
|
11431
|
+
for (const [k, v] of Object.entries(customHeaders)) {
|
|
11432
|
+
if (k.toLowerCase() === target) return v;
|
|
11433
|
+
}
|
|
11434
|
+
return void 0;
|
|
11435
|
+
};
|
|
11436
|
+
const effectiveLicenseKey = licenseKey || getHeader("x-license-key") || ((_a2 = getHeader("authorization")) == null ? void 0 : _a2.replace(/^Bearer\s+/i, "")) || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY || process.env.RETRIVORA_LICENSE_KEY : "") || "";
|
|
11437
|
+
if (!effectiveLicenseKey) {
|
|
11438
|
+
this.purgeCache(effectiveLicenseKey);
|
|
11384
11439
|
throw new LicenseValidationError("Missing RETRIVORA_LICENSE_KEY in request.");
|
|
11385
11440
|
}
|
|
11386
|
-
const cached = this.cache.get(
|
|
11441
|
+
const cached = this.cache.get(effectiveLicenseKey);
|
|
11387
11442
|
if (cached) {
|
|
11388
11443
|
const isFresh = Date.now() - cached.timestamp < _LicenseValidator.SUCCESS_CACHE_TTL_MS;
|
|
11389
11444
|
if (isFresh && cached.response.valid && cached.response.licenseStatus === "ACTIVE" && !cached.response.forceUpgrade) {
|
|
11390
11445
|
return cached.response;
|
|
11391
11446
|
} else {
|
|
11392
|
-
this.cache.delete(
|
|
11447
|
+
this.cache.delete(effectiveLicenseKey);
|
|
11393
11448
|
}
|
|
11394
11449
|
}
|
|
11395
11450
|
const base = retrivoraApiBase || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_RETRIVORA_API_BASE || process.env.RETRIVORA_API_BASE : "") || "/api/retrivora";
|
|
11396
11451
|
const validateUrl = `${base.replace(/\/$/, "")}/v1/license/validate`;
|
|
11397
|
-
let res;
|
|
11452
|
+
let res = null;
|
|
11398
11453
|
try {
|
|
11399
11454
|
res = await fetch(validateUrl, {
|
|
11400
11455
|
method: "POST",
|
|
11401
11456
|
cache: "no-store",
|
|
11402
11457
|
headers: __spreadValues({
|
|
11403
11458
|
"Content-Type": "application/json",
|
|
11404
|
-
"x-license-key":
|
|
11459
|
+
"x-license-key": effectiveLicenseKey,
|
|
11405
11460
|
"x-sdk-version": sdkVersion
|
|
11406
11461
|
}, customHeaders || {}),
|
|
11407
11462
|
body: JSON.stringify({
|
|
@@ -11413,8 +11468,40 @@ var _LicenseValidator = class _LicenseValidator {
|
|
|
11413
11468
|
})
|
|
11414
11469
|
});
|
|
11415
11470
|
} catch (err) {
|
|
11416
|
-
|
|
11417
|
-
|
|
11471
|
+
try {
|
|
11472
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId || "my-rag-app");
|
|
11473
|
+
const fallbackResp = {
|
|
11474
|
+
valid: true,
|
|
11475
|
+
licenseStatus: "ACTIVE",
|
|
11476
|
+
minimumSupportedVersion: "2.1.0",
|
|
11477
|
+
latestVersion: SDK_VERSION,
|
|
11478
|
+
forceUpgrade: false,
|
|
11479
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1e3).toISOString() : null,
|
|
11480
|
+
message: "Local license verification active."
|
|
11481
|
+
};
|
|
11482
|
+
this.cache.set(licenseKey, { response: fallbackResp, timestamp: Date.now() });
|
|
11483
|
+
return fallbackResp;
|
|
11484
|
+
} catch (e) {
|
|
11485
|
+
this.purgeCache(licenseKey);
|
|
11486
|
+
throw new LicenseValidationError(`License validation request failed: ${(err == null ? void 0 : err.message) || "Network error"}`);
|
|
11487
|
+
}
|
|
11488
|
+
}
|
|
11489
|
+
if (res && !res.ok) {
|
|
11490
|
+
try {
|
|
11491
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId || "my-rag-app");
|
|
11492
|
+
const fallbackResp = {
|
|
11493
|
+
valid: true,
|
|
11494
|
+
licenseStatus: "ACTIVE",
|
|
11495
|
+
minimumSupportedVersion: "2.1.0",
|
|
11496
|
+
latestVersion: SDK_VERSION,
|
|
11497
|
+
forceUpgrade: false,
|
|
11498
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1e3).toISOString() : null,
|
|
11499
|
+
message: "Local license verification active."
|
|
11500
|
+
};
|
|
11501
|
+
this.cache.set(licenseKey, { response: fallbackResp, timestamp: Date.now() });
|
|
11502
|
+
return fallbackResp;
|
|
11503
|
+
} catch (e) {
|
|
11504
|
+
}
|
|
11418
11505
|
}
|
|
11419
11506
|
const data = await res.json().catch(() => ({
|
|
11420
11507
|
valid: false,
|
package/dist/server.mjs
CHANGED
|
@@ -4723,7 +4723,7 @@ var ConfigValidator = class {
|
|
|
4723
4723
|
// package.json
|
|
4724
4724
|
var package_default = {
|
|
4725
4725
|
name: "@retrivora-ai/rag-engine",
|
|
4726
|
-
version: "2.2.
|
|
4726
|
+
version: "2.2.8",
|
|
4727
4727
|
description: "Retrivora AI is a plug-and-play AI engine for RAG chat experiences \u2014 generic vector DB + LLM provider, embeddable or standalone.",
|
|
4728
4728
|
author: "Abhinav Alkuchi",
|
|
4729
4729
|
license: "UNLICENSED",
|
|
@@ -10912,6 +10912,46 @@ function createHealthHandler(configOrPlugin, options) {
|
|
|
10912
10912
|
}
|
|
10913
10913
|
};
|
|
10914
10914
|
}
|
|
10915
|
+
function createLicenseHandler(configOrPlugin, options) {
|
|
10916
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
10917
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
10918
|
+
return async function POST(req) {
|
|
10919
|
+
var _a2;
|
|
10920
|
+
if (req) {
|
|
10921
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
10922
|
+
if (authResult) return authResult;
|
|
10923
|
+
}
|
|
10924
|
+
try {
|
|
10925
|
+
const body = await req.json().catch(() => ({}));
|
|
10926
|
+
const config = plugin.getConfig();
|
|
10927
|
+
const licenseKey = req.headers.get("x-license-key") || (body == null ? void 0 : body.licenseKey) || ((_a2 = req.headers.get("authorization")) == null ? void 0 : _a2.replace(/^Bearer\s+/i, "")) || config.licenseKey || process.env.RETRIVORA_LICENSE_KEY || process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY || "";
|
|
10928
|
+
const projectId = (body == null ? void 0 : body.projectId) || config.projectId || "my-rag-app";
|
|
10929
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId);
|
|
10930
|
+
return NextResponse.json({
|
|
10931
|
+
valid: true,
|
|
10932
|
+
licenseStatus: "ACTIVE",
|
|
10933
|
+
minimumSupportedVersion: "2.1.0",
|
|
10934
|
+
latestVersion: SDK_VERSION,
|
|
10935
|
+
forceUpgrade: false,
|
|
10936
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1e3).toISOString() : null,
|
|
10937
|
+
message: "License key is active and valid."
|
|
10938
|
+
});
|
|
10939
|
+
} catch (err) {
|
|
10940
|
+
return NextResponse.json(
|
|
10941
|
+
{
|
|
10942
|
+
valid: false,
|
|
10943
|
+
licenseStatus: "REVOKED",
|
|
10944
|
+
minimumSupportedVersion: "2.1.0",
|
|
10945
|
+
latestVersion: SDK_VERSION,
|
|
10946
|
+
forceUpgrade: false,
|
|
10947
|
+
expiresAt: null,
|
|
10948
|
+
message: (err == null ? void 0 : err.message) || "License validation failed."
|
|
10949
|
+
},
|
|
10950
|
+
{ status: 400 }
|
|
10951
|
+
);
|
|
10952
|
+
}
|
|
10953
|
+
};
|
|
10954
|
+
}
|
|
10915
10955
|
function createUploadHandler(configOrPlugin, options) {
|
|
10916
10956
|
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
10917
10957
|
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
@@ -11163,6 +11203,7 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
11163
11203
|
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
11164
11204
|
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
11165
11205
|
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
11206
|
+
const licenseHandler = createLicenseHandler(plugin, { onAuthorize });
|
|
11166
11207
|
async function routePostRequest(req, segment) {
|
|
11167
11208
|
switch (segment) {
|
|
11168
11209
|
case "chat":
|
|
@@ -11180,6 +11221,9 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
11180
11221
|
return historyHandler(req);
|
|
11181
11222
|
case "feedback":
|
|
11182
11223
|
return feedbackHandler(req);
|
|
11224
|
+
case "license/validate":
|
|
11225
|
+
case "v1/license/validate":
|
|
11226
|
+
return licenseHandler(req);
|
|
11183
11227
|
default:
|
|
11184
11228
|
return NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
11185
11229
|
}
|
|
@@ -11209,6 +11253,7 @@ function createRagHandler(configOrPlugin, options) {
|
|
|
11209
11253
|
try {
|
|
11210
11254
|
const url = new URL(req.url);
|
|
11211
11255
|
const pathname = url.pathname;
|
|
11256
|
+
if (pathname.includes("/license/validate")) return "v1/license/validate";
|
|
11212
11257
|
if (pathname.endsWith("/upload")) return "upload";
|
|
11213
11258
|
if (pathname.endsWith("/chat") || pathname.endsWith("/chat-sync")) return "chat";
|
|
11214
11259
|
if (pathname.endsWith("/health")) return "health";
|
|
@@ -11270,6 +11315,7 @@ var _LicenseValidator = class _LicenseValidator {
|
|
|
11270
11315
|
* Validate license status and SDK version against Retrivora License Service
|
|
11271
11316
|
*/
|
|
11272
11317
|
async validate(request) {
|
|
11318
|
+
var _a2;
|
|
11273
11319
|
const {
|
|
11274
11320
|
licenseKey,
|
|
11275
11321
|
projectId,
|
|
@@ -11279,29 +11325,38 @@ var _LicenseValidator = class _LicenseValidator {
|
|
|
11279
11325
|
retrivoraApiBase,
|
|
11280
11326
|
headers: customHeaders
|
|
11281
11327
|
} = request;
|
|
11282
|
-
|
|
11283
|
-
|
|
11328
|
+
const getHeader = (name) => {
|
|
11329
|
+
if (!customHeaders) return void 0;
|
|
11330
|
+
const target = name.toLowerCase();
|
|
11331
|
+
for (const [k, v] of Object.entries(customHeaders)) {
|
|
11332
|
+
if (k.toLowerCase() === target) return v;
|
|
11333
|
+
}
|
|
11334
|
+
return void 0;
|
|
11335
|
+
};
|
|
11336
|
+
const effectiveLicenseKey = licenseKey || getHeader("x-license-key") || ((_a2 = getHeader("authorization")) == null ? void 0 : _a2.replace(/^Bearer\s+/i, "")) || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY || process.env.RETRIVORA_LICENSE_KEY : "") || "";
|
|
11337
|
+
if (!effectiveLicenseKey) {
|
|
11338
|
+
this.purgeCache(effectiveLicenseKey);
|
|
11284
11339
|
throw new LicenseValidationError("Missing RETRIVORA_LICENSE_KEY in request.");
|
|
11285
11340
|
}
|
|
11286
|
-
const cached = this.cache.get(
|
|
11341
|
+
const cached = this.cache.get(effectiveLicenseKey);
|
|
11287
11342
|
if (cached) {
|
|
11288
11343
|
const isFresh = Date.now() - cached.timestamp < _LicenseValidator.SUCCESS_CACHE_TTL_MS;
|
|
11289
11344
|
if (isFresh && cached.response.valid && cached.response.licenseStatus === "ACTIVE" && !cached.response.forceUpgrade) {
|
|
11290
11345
|
return cached.response;
|
|
11291
11346
|
} else {
|
|
11292
|
-
this.cache.delete(
|
|
11347
|
+
this.cache.delete(effectiveLicenseKey);
|
|
11293
11348
|
}
|
|
11294
11349
|
}
|
|
11295
11350
|
const base = retrivoraApiBase || (typeof process !== "undefined" ? process.env.NEXT_PUBLIC_RETRIVORA_API_BASE || process.env.RETRIVORA_API_BASE : "") || "/api/retrivora";
|
|
11296
11351
|
const validateUrl = `${base.replace(/\/$/, "")}/v1/license/validate`;
|
|
11297
|
-
let res;
|
|
11352
|
+
let res = null;
|
|
11298
11353
|
try {
|
|
11299
11354
|
res = await fetch(validateUrl, {
|
|
11300
11355
|
method: "POST",
|
|
11301
11356
|
cache: "no-store",
|
|
11302
11357
|
headers: __spreadValues({
|
|
11303
11358
|
"Content-Type": "application/json",
|
|
11304
|
-
"x-license-key":
|
|
11359
|
+
"x-license-key": effectiveLicenseKey,
|
|
11305
11360
|
"x-sdk-version": sdkVersion
|
|
11306
11361
|
}, customHeaders || {}),
|
|
11307
11362
|
body: JSON.stringify({
|
|
@@ -11313,8 +11368,40 @@ var _LicenseValidator = class _LicenseValidator {
|
|
|
11313
11368
|
})
|
|
11314
11369
|
});
|
|
11315
11370
|
} catch (err) {
|
|
11316
|
-
|
|
11317
|
-
|
|
11371
|
+
try {
|
|
11372
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId || "my-rag-app");
|
|
11373
|
+
const fallbackResp = {
|
|
11374
|
+
valid: true,
|
|
11375
|
+
licenseStatus: "ACTIVE",
|
|
11376
|
+
minimumSupportedVersion: "2.1.0",
|
|
11377
|
+
latestVersion: SDK_VERSION,
|
|
11378
|
+
forceUpgrade: false,
|
|
11379
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1e3).toISOString() : null,
|
|
11380
|
+
message: "Local license verification active."
|
|
11381
|
+
};
|
|
11382
|
+
this.cache.set(licenseKey, { response: fallbackResp, timestamp: Date.now() });
|
|
11383
|
+
return fallbackResp;
|
|
11384
|
+
} catch (e) {
|
|
11385
|
+
this.purgeCache(licenseKey);
|
|
11386
|
+
throw new LicenseValidationError(`License validation request failed: ${(err == null ? void 0 : err.message) || "Network error"}`);
|
|
11387
|
+
}
|
|
11388
|
+
}
|
|
11389
|
+
if (res && !res.ok) {
|
|
11390
|
+
try {
|
|
11391
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId || "my-rag-app");
|
|
11392
|
+
const fallbackResp = {
|
|
11393
|
+
valid: true,
|
|
11394
|
+
licenseStatus: "ACTIVE",
|
|
11395
|
+
minimumSupportedVersion: "2.1.0",
|
|
11396
|
+
latestVersion: SDK_VERSION,
|
|
11397
|
+
forceUpgrade: false,
|
|
11398
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1e3).toISOString() : null,
|
|
11399
|
+
message: "Local license verification active."
|
|
11400
|
+
};
|
|
11401
|
+
this.cache.set(licenseKey, { response: fallbackResp, timestamp: Date.now() });
|
|
11402
|
+
return fallbackResp;
|
|
11403
|
+
} catch (e) {
|
|
11404
|
+
}
|
|
11318
11405
|
}
|
|
11319
11406
|
const data = await res.json().catch(() => ({
|
|
11320
11407
|
valid: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.8",
|
|
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",
|
|
@@ -46,7 +46,7 @@ const GEMINI_STYLES = `
|
|
|
46
46
|
}
|
|
47
47
|
`;
|
|
48
48
|
|
|
49
|
-
export function ChatWidget({ position = 'bottom-right', onAddToCart, apiUrl, retrivoraApiBase, headers }: ChatWidgetProps) {
|
|
49
|
+
export function ChatWidget({ position = 'bottom-right', onAddToCart, apiUrl, retrivoraApiBase, licenseKey: licenseKeyProp, headers }: ChatWidgetProps) {
|
|
50
50
|
const { ui, projectId } = useConfig();
|
|
51
51
|
const [isOpen, setIsOpen] = useState(false);
|
|
52
52
|
const [hasUnread, setHasUnread] = useState(false);
|
|
@@ -72,9 +72,26 @@ export function ChatWidget({ position = 'bottom-right', onAddToCart, apiUrl, ret
|
|
|
72
72
|
const handleOpen = async () => {
|
|
73
73
|
setIsValidating(true);
|
|
74
74
|
try {
|
|
75
|
-
const
|
|
75
|
+
const getHeader = (name: string) => {
|
|
76
|
+
if (!headers) return undefined;
|
|
77
|
+
const target = name.toLowerCase();
|
|
78
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
79
|
+
if (k.toLowerCase() === target) return v;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const resolvedLicenseKey =
|
|
85
|
+
licenseKeyProp ||
|
|
86
|
+
getHeader('x-license-key') ||
|
|
87
|
+
getHeader('authorization')?.replace(/^Bearer\s+/i, '') ||
|
|
88
|
+
(typeof process !== 'undefined'
|
|
89
|
+
? (process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY || process.env.RETRIVORA_LICENSE_KEY)
|
|
90
|
+
: '') ||
|
|
91
|
+
'';
|
|
92
|
+
|
|
76
93
|
await LicenseValidator.getInstance().validate({
|
|
77
|
-
licenseKey,
|
|
94
|
+
licenseKey: resolvedLicenseKey,
|
|
78
95
|
projectId,
|
|
79
96
|
retrivoraApiBase,
|
|
80
97
|
headers,
|
|
@@ -167,6 +184,7 @@ export function ChatWidget({ position = 'bottom-right', onAddToCart, apiUrl, ret
|
|
|
167
184
|
onAddToCart={onAddToCart}
|
|
168
185
|
apiUrl={apiUrl}
|
|
169
186
|
retrivoraApiBase={retrivoraApiBase}
|
|
187
|
+
licenseKey={licenseKeyProp}
|
|
170
188
|
headers={headers}
|
|
171
189
|
/>
|
|
172
190
|
{/* Pointer (Tail) */}
|
|
@@ -68,6 +68,7 @@ export function ChatWindow({
|
|
|
68
68
|
onAddToCart,
|
|
69
69
|
apiUrl,
|
|
70
70
|
retrivoraApiBase,
|
|
71
|
+
licenseKey: licenseKeyProp,
|
|
71
72
|
headers
|
|
72
73
|
}: ChatWindowProps) {
|
|
73
74
|
const { ui, projectId } = useConfig();
|
|
@@ -81,6 +82,7 @@ export function ChatWindow({
|
|
|
81
82
|
namespace: projectId,
|
|
82
83
|
apiUrl,
|
|
83
84
|
retrivoraApiBase,
|
|
85
|
+
licenseKey: licenseKeyProp,
|
|
84
86
|
headers,
|
|
85
87
|
});
|
|
86
88
|
|
|
@@ -98,9 +100,26 @@ export function ChatWindow({
|
|
|
98
100
|
let isMounted = true;
|
|
99
101
|
async function validateSessionLicense() {
|
|
100
102
|
try {
|
|
101
|
-
const
|
|
103
|
+
const getHeader = (name: string) => {
|
|
104
|
+
if (!headers) return undefined;
|
|
105
|
+
const target = name.toLowerCase();
|
|
106
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
107
|
+
if (k.toLowerCase() === target) return v;
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const resolvedLicenseKey =
|
|
113
|
+
licenseKeyProp ||
|
|
114
|
+
getHeader('x-license-key') ||
|
|
115
|
+
getHeader('authorization')?.replace(/^Bearer\s+/i, '') ||
|
|
116
|
+
(typeof process !== 'undefined'
|
|
117
|
+
? (process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY || process.env.RETRIVORA_LICENSE_KEY)
|
|
118
|
+
: '') ||
|
|
119
|
+
'';
|
|
120
|
+
|
|
102
121
|
await LicenseValidator.getInstance().validate({
|
|
103
|
-
licenseKey,
|
|
122
|
+
licenseKey: resolvedLicenseKey,
|
|
104
123
|
projectId,
|
|
105
124
|
retrivoraApiBase,
|
|
106
125
|
headers,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SDK_VERSION } from '../version';
|
|
2
2
|
import { SDKVersionUnsupportedError, LicenseValidationError } from '../exceptions';
|
|
3
|
+
import { LicenseVerifier } from './LicenseVerifier';
|
|
3
4
|
|
|
4
5
|
export interface LicenseValidationRequest {
|
|
5
6
|
licenseKey: string;
|
|
@@ -65,19 +66,37 @@ export class LicenseValidator {
|
|
|
65
66
|
headers: customHeaders,
|
|
66
67
|
} = request;
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
const getHeader = (name: string): string | undefined => {
|
|
70
|
+
if (!customHeaders) return undefined;
|
|
71
|
+
const target = name.toLowerCase();
|
|
72
|
+
for (const [k, v] of Object.entries(customHeaders)) {
|
|
73
|
+
if (k.toLowerCase() === target) return v;
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const effectiveLicenseKey =
|
|
79
|
+
licenseKey ||
|
|
80
|
+
getHeader('x-license-key') ||
|
|
81
|
+
getHeader('authorization')?.replace(/^Bearer\s+/i, '') ||
|
|
82
|
+
(typeof process !== 'undefined'
|
|
83
|
+
? (process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY || process.env.RETRIVORA_LICENSE_KEY)
|
|
84
|
+
: '') ||
|
|
85
|
+
'';
|
|
86
|
+
|
|
87
|
+
if (!effectiveLicenseKey) {
|
|
88
|
+
this.purgeCache(effectiveLicenseKey);
|
|
70
89
|
throw new LicenseValidationError('Missing RETRIVORA_LICENSE_KEY in request.');
|
|
71
90
|
}
|
|
72
91
|
|
|
73
92
|
// 1. Check successful 5-minute cache
|
|
74
|
-
const cached = this.cache.get(
|
|
93
|
+
const cached = this.cache.get(effectiveLicenseKey);
|
|
75
94
|
if (cached) {
|
|
76
95
|
const isFresh = Date.now() - cached.timestamp < LicenseValidator.SUCCESS_CACHE_TTL_MS;
|
|
77
96
|
if (isFresh && cached.response.valid && cached.response.licenseStatus === 'ACTIVE' && !cached.response.forceUpgrade) {
|
|
78
97
|
return cached.response;
|
|
79
98
|
} else {
|
|
80
|
-
this.cache.delete(
|
|
99
|
+
this.cache.delete(effectiveLicenseKey);
|
|
81
100
|
}
|
|
82
101
|
}
|
|
83
102
|
|
|
@@ -85,14 +104,14 @@ export class LicenseValidator {
|
|
|
85
104
|
const base = retrivoraApiBase || (typeof process !== 'undefined' ? process.env.NEXT_PUBLIC_RETRIVORA_API_BASE || process.env.RETRIVORA_API_BASE : '') || '/api/retrivora';
|
|
86
105
|
const validateUrl = `${base.replace(/\/$/, '')}/v1/license/validate`;
|
|
87
106
|
|
|
88
|
-
let res: Response;
|
|
107
|
+
let res: Response | null = null;
|
|
89
108
|
try {
|
|
90
109
|
res = await fetch(validateUrl, {
|
|
91
110
|
method: 'POST',
|
|
92
111
|
cache: 'no-store',
|
|
93
112
|
headers: {
|
|
94
113
|
'Content-Type': 'application/json',
|
|
95
|
-
'x-license-key':
|
|
114
|
+
'x-license-key': effectiveLicenseKey,
|
|
96
115
|
'x-sdk-version': sdkVersion,
|
|
97
116
|
...(customHeaders || {}),
|
|
98
117
|
},
|
|
@@ -105,12 +124,45 @@ export class LicenseValidator {
|
|
|
105
124
|
}),
|
|
106
125
|
});
|
|
107
126
|
} catch (err: any) {
|
|
108
|
-
// Fallback: If network error occurs,
|
|
109
|
-
|
|
110
|
-
|
|
127
|
+
// Fallback: If network error occurs, verify locally via RSA LicenseVerifier
|
|
128
|
+
try {
|
|
129
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId || 'my-rag-app');
|
|
130
|
+
const fallbackResp: LicenseValidationResponse = {
|
|
131
|
+
valid: true,
|
|
132
|
+
licenseStatus: 'ACTIVE',
|
|
133
|
+
minimumSupportedVersion: '2.1.0',
|
|
134
|
+
latestVersion: SDK_VERSION,
|
|
135
|
+
forceUpgrade: false,
|
|
136
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1000).toISOString() : null,
|
|
137
|
+
message: 'Local license verification active.',
|
|
138
|
+
};
|
|
139
|
+
this.cache.set(licenseKey, { response: fallbackResp, timestamp: Date.now() });
|
|
140
|
+
return fallbackResp;
|
|
141
|
+
} catch {
|
|
142
|
+
this.purgeCache(licenseKey);
|
|
143
|
+
throw new LicenseValidationError(`License validation request failed: ${err?.message || 'Network error'}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (res && !res.ok) {
|
|
148
|
+
// Attempt local verification fallback if API route returned 404 or non-OK response
|
|
149
|
+
try {
|
|
150
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId || 'my-rag-app');
|
|
151
|
+
const fallbackResp: LicenseValidationResponse = {
|
|
152
|
+
valid: true,
|
|
153
|
+
licenseStatus: 'ACTIVE',
|
|
154
|
+
minimumSupportedVersion: '2.1.0',
|
|
155
|
+
latestVersion: SDK_VERSION,
|
|
156
|
+
forceUpgrade: false,
|
|
157
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1000).toISOString() : null,
|
|
158
|
+
message: 'Local license verification active.',
|
|
159
|
+
};
|
|
160
|
+
this.cache.set(licenseKey, { response: fallbackResp, timestamp: Date.now() });
|
|
161
|
+
return fallbackResp;
|
|
162
|
+
} catch { /* proceed to parse error response */ }
|
|
111
163
|
}
|
|
112
164
|
|
|
113
|
-
const data: LicenseValidationResponse = await res
|
|
165
|
+
const data: LicenseValidationResponse = await res!.json().catch(() => ({
|
|
114
166
|
valid: false,
|
|
115
167
|
licenseStatus: 'REVOKED' as const,
|
|
116
168
|
minimumSupportedVersion: '2.1.0',
|
package/src/handlers/index.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { ChatMessage, ChatResponse } from '../types';
|
|
|
5
5
|
import { DocumentParser } from '../utils/DocumentParser';
|
|
6
6
|
import { UITransformer } from '../utils/UITransformer';
|
|
7
7
|
import { DatabaseStorage, HistoryMessage } from '../core/DatabaseStorage';
|
|
8
|
+
import { LicenseVerifier } from '../core/LicenseVerifier';
|
|
9
|
+
import { SDK_VERSION } from '../version';
|
|
8
10
|
|
|
9
11
|
export interface HandlerOptions {
|
|
10
12
|
onAuthorize?: (req: NextRequest) => boolean | Promise<boolean> | Response | Promise<Response>;
|
|
@@ -147,8 +149,6 @@ function getOrCreatePlugin(configOrPlugin: Partial<RagConfig> | VectorPlugin | u
|
|
|
147
149
|
|
|
148
150
|
// ─── Telemetry Reporter Helper ───────────────────────────────────────────────
|
|
149
151
|
|
|
150
|
-
import { SDK_VERSION } from '../version';
|
|
151
|
-
|
|
152
152
|
/**
|
|
153
153
|
* Asynchronously sends telemetry payload to telemetryUrl when telemetry is enabled
|
|
154
154
|
* or when a licenseKey is set. Non-blocking.
|
|
@@ -596,6 +596,64 @@ export function createHealthHandler(
|
|
|
596
596
|
};
|
|
597
597
|
}
|
|
598
598
|
|
|
599
|
+
/**
|
|
600
|
+
* createLicenseHandler — factory for the license validation endpoint (/v1/license/validate).
|
|
601
|
+
*/
|
|
602
|
+
export function createLicenseHandler(
|
|
603
|
+
configOrPlugin?: Partial<RagConfig> | VectorPlugin,
|
|
604
|
+
options?: HandlerOptions
|
|
605
|
+
) {
|
|
606
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
607
|
+
const onAuthorize = options?.onAuthorize;
|
|
608
|
+
|
|
609
|
+
return async function POST(req: NextRequest) {
|
|
610
|
+
if (req) {
|
|
611
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
612
|
+
if (authResult) return authResult as any;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
try {
|
|
616
|
+
const body = await req.json().catch(() => ({}));
|
|
617
|
+
const config = plugin.getConfig();
|
|
618
|
+
const licenseKey =
|
|
619
|
+
req.headers.get('x-license-key') ||
|
|
620
|
+
body?.licenseKey ||
|
|
621
|
+
req.headers.get('authorization')?.replace(/^Bearer\s+/i, '') ||
|
|
622
|
+
config.licenseKey ||
|
|
623
|
+
process.env.RETRIVORA_LICENSE_KEY ||
|
|
624
|
+
process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY ||
|
|
625
|
+
'';
|
|
626
|
+
|
|
627
|
+
const projectId = body?.projectId || config.projectId || 'my-rag-app';
|
|
628
|
+
|
|
629
|
+
const payload = LicenseVerifier.verify(licenseKey, projectId);
|
|
630
|
+
|
|
631
|
+
return NextResponse.json({
|
|
632
|
+
valid: true,
|
|
633
|
+
licenseStatus: 'ACTIVE',
|
|
634
|
+
minimumSupportedVersion: '2.1.0',
|
|
635
|
+
latestVersion: SDK_VERSION,
|
|
636
|
+
forceUpgrade: false,
|
|
637
|
+
expiresAt: payload.expiresAt ? new Date(payload.expiresAt * 1000).toISOString() : null,
|
|
638
|
+
message: 'License key is active and valid.',
|
|
639
|
+
});
|
|
640
|
+
} catch (err: any) {
|
|
641
|
+
return NextResponse.json(
|
|
642
|
+
{
|
|
643
|
+
valid: false,
|
|
644
|
+
licenseStatus: 'REVOKED',
|
|
645
|
+
minimumSupportedVersion: '2.1.0',
|
|
646
|
+
latestVersion: SDK_VERSION,
|
|
647
|
+
forceUpgrade: false,
|
|
648
|
+
expiresAt: null,
|
|
649
|
+
message: err?.message || 'License validation failed.',
|
|
650
|
+
},
|
|
651
|
+
{ status: 400 }
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
|
|
599
657
|
/**
|
|
600
658
|
* createUploadHandler — factory for the file upload ingestion endpoint.
|
|
601
659
|
*/
|
|
@@ -932,6 +990,7 @@ export function createRagHandler(
|
|
|
932
990
|
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
933
991
|
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
934
992
|
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
993
|
+
const licenseHandler = createLicenseHandler(plugin, { onAuthorize });
|
|
935
994
|
|
|
936
995
|
async function routePostRequest(req: any, segment: string) {
|
|
937
996
|
switch (segment) {
|
|
@@ -950,6 +1009,9 @@ export function createRagHandler(
|
|
|
950
1009
|
return historyHandler(req);
|
|
951
1010
|
case 'feedback':
|
|
952
1011
|
return feedbackHandler(req);
|
|
1012
|
+
case 'license/validate':
|
|
1013
|
+
case 'v1/license/validate':
|
|
1014
|
+
return licenseHandler(req);
|
|
953
1015
|
default:
|
|
954
1016
|
return NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
955
1017
|
}
|
|
@@ -983,6 +1045,7 @@ export function createRagHandler(
|
|
|
983
1045
|
try {
|
|
984
1046
|
const url = new URL(req.url);
|
|
985
1047
|
const pathname = url.pathname;
|
|
1048
|
+
if (pathname.includes('/license/validate')) return 'v1/license/validate';
|
|
986
1049
|
if (pathname.endsWith('/upload')) return 'upload';
|
|
987
1050
|
if (pathname.endsWith('/chat') || pathname.endsWith('/chat-sync')) return 'chat';
|
|
988
1051
|
if (pathname.endsWith('/health')) return 'health';
|