@retrivora-ai/rag-engine 2.0.4 → 2.0.6

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.
@@ -2093,6 +2093,285 @@ var import_server = require("next/server");
2093
2093
  // src/core/ConfigResolver.ts
2094
2094
  init_templateUtils();
2095
2095
 
2096
+ // src/core/LicenseVerifier.ts
2097
+ var crypto = __toESM(require("crypto"));
2098
+
2099
+ // src/exceptions/index.ts
2100
+ var RetrivoraError = class extends Error {
2101
+ constructor(message, code, details) {
2102
+ super(message);
2103
+ this.name = new.target.name;
2104
+ this.code = code;
2105
+ this.details = details;
2106
+ }
2107
+ };
2108
+ var ProviderNotFoundException = class extends RetrivoraError {
2109
+ constructor(providerType, provider, details) {
2110
+ super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
2111
+ }
2112
+ };
2113
+ var EmbeddingFailedException = class extends RetrivoraError {
2114
+ constructor(message = "Embedding generation failed", details) {
2115
+ super(message, "EMBEDDING_FAILED", details);
2116
+ }
2117
+ };
2118
+ var RetrievalException = class extends RetrivoraError {
2119
+ constructor(message = "Retrieval failed", details) {
2120
+ super(message, "RETRIEVAL_FAILED", details);
2121
+ }
2122
+ };
2123
+ var RateLimitException = class extends RetrivoraError {
2124
+ constructor(message = "Provider rate limit exceeded", details) {
2125
+ super(message, "RATE_LIMITED", details);
2126
+ }
2127
+ };
2128
+ var ConfigurationException = class extends RetrivoraError {
2129
+ constructor(message, details) {
2130
+ super(message, "CONFIGURATION_ERROR", details);
2131
+ }
2132
+ };
2133
+ var AuthenticationException = class extends RetrivoraError {
2134
+ constructor(message = "Provider authentication failed", details) {
2135
+ super(message, "AUTHENTICATION_ERROR", details);
2136
+ }
2137
+ };
2138
+ function wrapError(err, defaultCode, defaultMessage) {
2139
+ var _a2;
2140
+ if (err instanceof RetrivoraError) {
2141
+ return err;
2142
+ }
2143
+ const error = err;
2144
+ const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
2145
+ const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status);
2146
+ const code = error == null ? void 0 : error.code;
2147
+ if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
2148
+ return new RateLimitException(message, err);
2149
+ }
2150
+ if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
2151
+ return new AuthenticationException(message, err);
2152
+ }
2153
+ switch (defaultCode) {
2154
+ case "PROVIDER_NOT_FOUND":
2155
+ return new ProviderNotFoundException("provider", message, err);
2156
+ case "EMBEDDING_FAILED":
2157
+ return new EmbeddingFailedException(message, err);
2158
+ case "RETRIEVAL_FAILED":
2159
+ return new RetrievalException(message, err);
2160
+ case "RATE_LIMITED":
2161
+ return new RateLimitException(message, err);
2162
+ case "CONFIGURATION_ERROR":
2163
+ return new ConfigurationException(message, err);
2164
+ case "AUTHENTICATION_ERROR":
2165
+ return new AuthenticationException(message, err);
2166
+ default:
2167
+ return new RetrivoraError(message, defaultCode, err);
2168
+ }
2169
+ }
2170
+
2171
+ // src/core/LicenseVerifier.ts
2172
+ var LicenseVerifier = class {
2173
+ /**
2174
+ * Decodes, verifies signature, and checks metadata of a license key.
2175
+ *
2176
+ * @param licenseKey - Base64url signed JWT license key.
2177
+ * @param currentProjectId - Project namespace ID.
2178
+ * @param publicKeyOverride - Optional override for unit/integration tests.
2179
+ */
2180
+ static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
2181
+ const isProduction = process.env.NODE_ENV === "production";
2182
+ const now = Date.now();
2183
+ if (licenseKey) {
2184
+ const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
2185
+ const cached = this.cache.get(cacheKey);
2186
+ if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
2187
+ const currentTimestampSec = Math.floor(now / 1e3);
2188
+ if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
2189
+ this.cache.delete(cacheKey);
2190
+ } else {
2191
+ return cached.payload;
2192
+ }
2193
+ }
2194
+ }
2195
+ if (!licenseKey) {
2196
+ if (isProduction) {
2197
+ throw new ConfigurationException(
2198
+ "[Retrivora SDK] License key (licenseKey) is required in production environments."
2199
+ );
2200
+ }
2201
+ console.warn(
2202
+ `\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
2203
+ );
2204
+ return {
2205
+ projectId: currentProjectId,
2206
+ expiresAt: Math.floor(Date.now() / 1e3) + 86400,
2207
+ // Valid for 24h
2208
+ tier: "hobby"
2209
+ };
2210
+ }
2211
+ try {
2212
+ const parts = licenseKey.split(".");
2213
+ if (parts.length !== 3) {
2214
+ throw new Error("Malformed token structure (expected 3 parts).");
2215
+ }
2216
+ const [headerB64, payloadB64, signatureB64] = parts;
2217
+ const dataToVerify = `${headerB64}.${payloadB64}`;
2218
+ const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
2219
+ const signature = Buffer.from(signatureB64, "base64url");
2220
+ const data = Buffer.from(dataToVerify);
2221
+ const isValid = crypto.verify(
2222
+ "sha256",
2223
+ data,
2224
+ publicKey,
2225
+ signature
2226
+ );
2227
+ if (!isValid) {
2228
+ throw new Error("Signature verification failed.");
2229
+ }
2230
+ const payload = JSON.parse(
2231
+ Buffer.from(payloadB64, "base64url").toString("utf8")
2232
+ );
2233
+ if (!payload.projectId) {
2234
+ throw new Error('License payload is missing "projectId".');
2235
+ }
2236
+ if (payload.projectId !== currentProjectId) {
2237
+ throw new Error(
2238
+ `Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
2239
+ );
2240
+ }
2241
+ if (!payload.expiresAt) {
2242
+ throw new Error('License payload is missing expiration ("expiresAt").');
2243
+ }
2244
+ const currentTimestampSec = Math.floor(Date.now() / 1e3);
2245
+ if (currentTimestampSec > payload.expiresAt) {
2246
+ throw new Error(
2247
+ `License key has expired. Expiration: ${new Date(
2248
+ payload.expiresAt * 1e3
2249
+ ).toDateString()}`
2250
+ );
2251
+ }
2252
+ if (isProduction && provider) {
2253
+ const tier = (payload.tier || "").toLowerCase();
2254
+ const normalizedProvider = provider.toLowerCase();
2255
+ if (tier === "hobby") {
2256
+ const allowedHobby = ["postgresql", "pgvector", "supabase"];
2257
+ if (!allowedHobby.includes(normalizedProvider)) {
2258
+ throw new Error(
2259
+ `The database provider "${provider}" is not allowed on the Hobby tier. Hobby tier is restricted to PostgreSQL and Supabase. Please upgrade to a Developer Pro or Enterprise plan.`
2260
+ );
2261
+ }
2262
+ } else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth" || tier === "free_trial" || tier === "free_tier" || tier === "free") {
2263
+ const allowedPro = [
2264
+ "postgresql",
2265
+ "pgvector",
2266
+ "supabase",
2267
+ "pinecone",
2268
+ "qdrant",
2269
+ "mongodb",
2270
+ "milvus",
2271
+ "chroma",
2272
+ "chromadb"
2273
+ ];
2274
+ if (!allowedPro.includes(normalizedProvider)) {
2275
+ throw new Error(
2276
+ `The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
2277
+ );
2278
+ }
2279
+ }
2280
+ }
2281
+ if (licenseKey) {
2282
+ const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
2283
+ this.cache.set(cacheKey, { payload, cachedAt: now });
2284
+ }
2285
+ return payload;
2286
+ } catch (err) {
2287
+ const message = err instanceof Error ? err.message : String(err);
2288
+ throw new ConfigurationException(
2289
+ `[Retrivora SDK] License key validation failed: ${message}`
2290
+ );
2291
+ }
2292
+ }
2293
+ static async verifyIP(licenseKey) {
2294
+ if (!licenseKey) return;
2295
+ try {
2296
+ const parts = licenseKey.split(".");
2297
+ if (parts.length !== 3) return;
2298
+ const [, payloadB64] = parts;
2299
+ const payload = JSON.parse(
2300
+ Buffer.from(payloadB64, "base64url").toString("utf8")
2301
+ );
2302
+ const tier = (payload.tier || "").toLowerCase();
2303
+ if (tier === "enterprise" || tier === "custom") {
2304
+ return;
2305
+ }
2306
+ if (payload.ipv4 || payload.ipv6) {
2307
+ let currentIpv4 = "";
2308
+ let currentIpv6 = "";
2309
+ try {
2310
+ const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
2311
+ const data = await res.json();
2312
+ currentIpv4 = data.ip;
2313
+ } catch (e) {
2314
+ }
2315
+ try {
2316
+ const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
2317
+ const data = await res.json();
2318
+ currentIpv6 = data.ip;
2319
+ } catch (e) {
2320
+ }
2321
+ const localIps = [];
2322
+ try {
2323
+ const osModule = require("os");
2324
+ const interfaces = osModule.networkInterfaces();
2325
+ for (const name of Object.keys(interfaces)) {
2326
+ for (const iface of interfaces[name] || []) {
2327
+ if (!iface.internal) {
2328
+ localIps.push(iface.address);
2329
+ }
2330
+ }
2331
+ }
2332
+ } catch (e) {
2333
+ }
2334
+ const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
2335
+ const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
2336
+ if (payload.ipv4 && payload.ipv6) {
2337
+ if (!isIpv4Match && !isIpv6Match) {
2338
+ throw new Error(
2339
+ `License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}, IPv6: ${payload.ipv6}) and cannot be used on this machine.`
2340
+ );
2341
+ }
2342
+ } else if (payload.ipv4 && !isIpv4Match) {
2343
+ throw new Error(
2344
+ `License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
2345
+ );
2346
+ } else if (payload.ipv6 && !isIpv6Match) {
2347
+ throw new Error(
2348
+ `License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
2349
+ );
2350
+ }
2351
+ }
2352
+ } catch (err) {
2353
+ if (err.message.includes("License key access restricted")) {
2354
+ throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
2355
+ }
2356
+ }
2357
+ }
2358
+ };
2359
+ // A simple in-memory cache to save CPU overhead of cryptographic signature checks.
2360
+ LicenseVerifier.cache = /* @__PURE__ */ new Map();
2361
+ LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
2362
+ // Cache verified license for 60 seconds
2363
+ // Retrivora's Public Key used to verify the license key signature.
2364
+ // In production, this matches the private key held by Retrivora SaaS.
2365
+ LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
2366
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
2367
+ XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
2368
+ xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
2369
+ NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
2370
+ iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
2371
+ +Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
2372
+ MwIDAQAB
2373
+ -----END PUBLIC KEY-----`;
2374
+
2096
2375
  // src/config/constants.ts
2097
2376
  var VECTOR_DB_PROVIDERS = [
2098
2377
  "pinecone",
@@ -2162,14 +2441,12 @@ function readEnum(env, name, fallback, allowed) {
2162
2441
  throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
2163
2442
  }
2164
2443
  function getEnvConfig(env = process.env, base) {
2165
- var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua;
2444
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab, _bb, _cb, _db, _eb, _fb, _gb, _hb, _ib, _jb, _kb, _lb, _mb, _nb, _ob, _pb, _qb, _rb, _sb, _tb, _ub, _vb, _wb;
2166
2445
  const projectId = (_c = (_b = (_a2 = readString(env, "RAG_PROJECT_ID")) != null ? _a2 : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
2167
2446
  const licenseKey = (_g2 = (_f = (_e = (_d = readString(env, "RAG_LICENSE_KEY")) != null ? _d : readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _e : readString(env, "NEXT_PUBLIC_RETRIVORA_LICENSE_KEY")) != null ? _f : readString(env, "LICENSE_KEY")) != null ? _g2 : base == null ? void 0 : base.licenseKey;
2168
2447
  const telemetryEnabled = readString(env, "TELEMETRY_ENABLED") === "true" || readString(env, "NEXT_PUBLIC_TELEMETRY_ENABLED") === "true" || ((_h = base == null ? void 0 : base.telemetry) == null ? void 0 : _h.enabled) || Boolean(licenseKey);
2169
2448
  const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
2170
- const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
2171
- const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
2172
- const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
2449
+ const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 768);
2173
2450
  const vectorDbOptions = {};
2174
2451
  if (vectorProvider === "pinecone") {
2175
2452
  vectorDbOptions.apiKey = (_l = (_k = readString(env, "PINECONE_API_KEY")) != null ? _k : (_j = (_i = base == null ? void 0 : base.vectorDb) == null ? void 0 : _i.options) == null ? void 0 : _j.apiKey) != null ? _l : "";
@@ -2234,65 +2511,88 @@ function getEnvConfig(env = process.env, base) {
2234
2511
  rest: "default",
2235
2512
  custom: "default"
2236
2513
  };
2514
+ const isFreeTier = (() => {
2515
+ if (!licenseKey) return true;
2516
+ try {
2517
+ const payload = LicenseVerifier.verify(licenseKey, projectId);
2518
+ const tier = (payload.tier || "").toLowerCase();
2519
+ return tier === "free_trial" || tier === "free_tier" || tier === "free" || tier === "hobby";
2520
+ } catch (e) {
2521
+ return true;
2522
+ }
2523
+ })();
2524
+ const DEFAULT_FREE_GATEWAY = "https://llm.retrivora.com/api/v1";
2525
+ const defaultLlmProvider = isFreeTier ? "universal_rest" : "universal_rest";
2526
+ const llmProvider = (_na = (_ma = readEnum(env, "LLM_PROVIDER", defaultLlmProvider, LLM_PROVIDERS)) != null ? _ma : (_la = base == null ? void 0 : base.llm) == null ? void 0 : _la.provider) != null ? _na : defaultLlmProvider;
2527
+ const llmBaseUrl = (_qa = (_pa = readString(env, "LLM_BASE_URL")) != null ? _pa : (_oa = base == null ? void 0 : base.llm) == null ? void 0 : _oa.baseUrl) != null ? _qa : DEFAULT_FREE_GATEWAY;
2528
+ const llmModel = (_ua = (_sa = readString(env, "LLM_MODEL")) != null ? _sa : (_ra = base == null ? void 0 : base.llm) == null ? void 0 : _ra.model) != null ? _ua : isFreeTier ? "llama-3.1-8b-instant" : (_ta = DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _ta : "gpt-4o";
2529
+ const llmApiKey = (_ya = (_xa = (_va = llmApiKeyByProvider[llmProvider]) != null ? _va : readString(env, "LLM_API_KEY")) != null ? _xa : (_wa = base == null ? void 0 : base.llm) == null ? void 0 : _wa.apiKey) != null ? _ya : "sk-retrivora-cancer-280590";
2530
+ const llmProfile = (_Ca = (_Ba = readString(env, "LLM_UNIVERSAL_PROFILE")) != null ? _Ba : (_Aa = (_za = base == null ? void 0 : base.llm) == null ? void 0 : _za.options) == null ? void 0 : _Aa.profile) != null ? _Ca : "litellm";
2531
+ const defaultEmbeddingProvider = isFreeTier ? "universal_rest" : "universal_rest";
2532
+ const embeddingProvider = (_Fa = (_Ea = readEnum(env, "EMBEDDING_PROVIDER", defaultEmbeddingProvider, EMBEDDING_PROVIDERS)) != null ? _Ea : (_Da = base == null ? void 0 : base.embedding) == null ? void 0 : _Da.provider) != null ? _Fa : defaultEmbeddingProvider;
2533
+ const embeddingBaseUrl = (_Ia = (_Ha = readString(env, "EMBEDDING_BASE_URL")) != null ? _Ha : (_Ga = base == null ? void 0 : base.embedding) == null ? void 0 : _Ga.baseUrl) != null ? _Ia : DEFAULT_FREE_GATEWAY;
2534
+ const embeddingModel = (_La = (_Ka = readString(env, "EMBEDDING_MODEL")) != null ? _Ka : (_Ja = base == null ? void 0 : base.embedding) == null ? void 0 : _Ja.model) != null ? _La : "text-embedding-004";
2535
+ const embeddingApiKey = (_Qa = (_Pa = (_Na = (_Ma = embeddingApiKeyByProvider[embeddingProvider]) != null ? _Ma : readString(env, "EMBEDDING_API_KEY")) != null ? _Na : readString(env, "LLM_API_KEY")) != null ? _Pa : (_Oa = base == null ? void 0 : base.embedding) == null ? void 0 : _Oa.apiKey) != null ? _Qa : "sk-retrivora-cancer-280590";
2536
+ const embeddingProfile = (_Ua = (_Ta = readString(env, "EMBEDDING_UNIVERSAL_PROFILE")) != null ? _Ta : (_Sa = (_Ra = base == null ? void 0 : base.embedding) == null ? void 0 : _Ra.options) == null ? void 0 : _Sa.profile) != null ? _Ua : "litellm";
2237
2537
  return __spreadProps(__spreadValues({
2238
2538
  projectId,
2239
- licenseKey: (_ma = (_la = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _la : readString(env, "LICENSE_KEY")) != null ? _ma : base == null ? void 0 : base.licenseKey,
2539
+ licenseKey,
2240
2540
  vectorDb: {
2241
2541
  provider: vectorProvider,
2242
- indexName: (_oa = (_na = readString(env, "VECTOR_DB_INDEX")) != null ? _na : vectorDbOptions.indexName) != null ? _oa : "rag-index",
2542
+ indexName: (_Wa = (_Va = readString(env, "VECTOR_DB_INDEX")) != null ? _Va : vectorDbOptions.indexName) != null ? _Wa : "rag-index",
2243
2543
  options: vectorDbOptions
2244
2544
  },
2245
2545
  llm: {
2246
2546
  provider: llmProvider,
2247
- model: (_qa = (_pa = readString(env, "LLM_MODEL")) != null ? _pa : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _qa : "gpt-4o",
2248
- apiKey: (_ra = llmApiKeyByProvider[llmProvider]) != null ? _ra : "",
2249
- baseUrl: readString(env, "LLM_BASE_URL"),
2547
+ model: llmModel,
2548
+ apiKey: llmApiKey,
2549
+ baseUrl: llmBaseUrl,
2250
2550
  systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
2251
2551
  maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
2252
2552
  temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
2253
2553
  options: {
2254
- profile: readString(env, "LLM_UNIVERSAL_PROFILE"),
2554
+ profile: llmProfile,
2255
2555
  thinking: readString(env, "LLM_THINKING") === "true" || readString(env, "LLM_THINKING") === "enabled" ? true : readString(env, "LLM_THINKING") === "false" ? false : void 0,
2256
2556
  thinkingBudget: env.LLM_THINKING_BUDGET ? parseInt(env.LLM_THINKING_BUDGET, 10) : void 0
2257
2557
  }
2258
2558
  },
2259
2559
  embedding: {
2260
2560
  provider: embeddingProvider,
2261
- model: (_sa = readString(env, "EMBEDDING_MODEL")) != null ? _sa : "text-embedding-3-small",
2262
- apiKey: embeddingApiKeyByProvider[embeddingProvider],
2263
- baseUrl: readString(env, "EMBEDDING_BASE_URL"),
2561
+ model: embeddingModel,
2562
+ apiKey: embeddingApiKey,
2563
+ baseUrl: embeddingBaseUrl,
2264
2564
  dimensions: embeddingDimensions,
2265
2565
  queryPrefix: readString(env, "EMBEDDING_QUERY_PREFIX"),
2266
2566
  documentPrefix: readString(env, "EMBEDDING_DOCUMENT_PREFIX"),
2267
2567
  options: {
2268
- profile: readString(env, "EMBEDDING_UNIVERSAL_PROFILE")
2568
+ profile: embeddingProfile
2269
2569
  }
2270
2570
  },
2271
2571
  ui: {
2272
- title: (_ua = (_ta = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _ta : readString(env, "UI_TITLE")) != null ? _ua : "AI Assistant",
2273
- subtitle: (_wa = (_va = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _va : readString(env, "UI_SUBTITLE")) != null ? _wa : "Powered by RAG",
2274
- primaryColor: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _xa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ya : "#10b981",
2275
- accentColor: (_Aa = (_za = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _za : readString(env, "UI_ACCENT_COLOR")) != null ? _Aa : "#3b82f6",
2276
- logoUrl: (_Ba = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _Ba : readString(env, "UI_LOGO_URL"),
2277
- placeholder: (_Da = (_Ca = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _Ca : readString(env, "UI_PLACEHOLDER")) != null ? _Da : "Ask me anything\u2026",
2278
- showSources: ((_Fa = (_Ea = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _Ea : readString(env, "UI_SHOW_SOURCES")) != null ? _Fa : "true") !== "false",
2279
- welcomeMessage: (_Ha = (_Ga = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _Ga : readString(env, "UI_WELCOME_MESSAGE")) != null ? _Ha : "Hello! I'm your AI assistant. Ask me anything about your documents.",
2280
- visualStyle: (_Ja = (_Ia = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Ia : readString(env, "UI_VISUAL_STYLE")) != null ? _Ja : "glass",
2281
- borderRadius: (_La = (_Ka = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Ka : readString(env, "UI_BORDER_RADIUS")) != null ? _La : "xl",
2282
- allowUpload: ((_Na = (_Ma = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ma : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Na : "false") === "true"
2572
+ title: (_Ya = (_Xa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _Xa : readString(env, "UI_TITLE")) != null ? _Ya : "AI Assistant",
2573
+ subtitle: (__a = (_Za = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _Za : readString(env, "UI_SUBTITLE")) != null ? __a : "Powered by RAG",
2574
+ primaryColor: (_ab = (_$a = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _$a : readString(env, "UI_PRIMARY_COLOR")) != null ? _ab : "#10b981",
2575
+ accentColor: (_cb = (_bb = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _bb : readString(env, "UI_ACCENT_COLOR")) != null ? _cb : "#3b82f6",
2576
+ logoUrl: (_db = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _db : readString(env, "UI_LOGO_URL"),
2577
+ placeholder: (_fb = (_eb = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _eb : readString(env, "UI_PLACEHOLDER")) != null ? _fb : "Ask me anything\u2026",
2578
+ showSources: ((_hb = (_gb = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _gb : readString(env, "UI_SHOW_SOURCES")) != null ? _hb : "true") !== "false",
2579
+ welcomeMessage: (_jb = (_ib = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _ib : readString(env, "UI_WELCOME_MESSAGE")) != null ? _jb : "Hello! I'm your AI assistant. Ask me anything about your documents.",
2580
+ visualStyle: (_lb = (_kb = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _kb : readString(env, "UI_VISUAL_STYLE")) != null ? _lb : "glass",
2581
+ borderRadius: (_nb = (_mb = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _mb : readString(env, "UI_BORDER_RADIUS")) != null ? _nb : "xl",
2582
+ allowUpload: ((_pb = (_ob = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _ob : readString(env, "UI_ALLOW_UPLOAD")) != null ? _pb : "false") === "true"
2283
2583
  },
2284
2584
  rag: {
2285
2585
  topK: readNumber(env, "RAG_TOP_K", 5),
2286
2586
  scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
2287
2587
  chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
2288
2588
  chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
2289
- filterableFields: (_Oa = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Oa.split(",").map((f) => f.trim()),
2589
+ filterableFields: (_qb = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _qb.split(",").map((f) => f.trim()),
2290
2590
  // Query pipeline toggles — read from .env.local
2291
2591
  useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
2292
2592
  useReranking: readString(env, "RAG_USE_RERANKING") === "true",
2293
2593
  useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
2294
- architecture: (_Pa = readString(env, "RAG_ARCHITECTURE")) != null ? _Pa : "simple",
2295
- chunkingStrategy: (_Qa = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _Qa : "recursive",
2594
+ architecture: (_rb = readString(env, "RAG_ARCHITECTURE")) != null ? _rb : "simple",
2595
+ chunkingStrategy: (_sb = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _sb : "recursive",
2296
2596
  uiMapping: (() => {
2297
2597
  const raw = readString(env, "RAG_UI_MAPPING");
2298
2598
  if (!raw) return void 0;
@@ -2305,7 +2605,7 @@ function getEnvConfig(env = process.env, base) {
2305
2605
  },
2306
2606
  telemetry: {
2307
2607
  enabled: telemetryEnabled,
2308
- url: (_Ua = (_Ta = (_Ra = readString(env, "TELEMETRY_URL")) != null ? _Ra : readString(env, "NEXT_PUBLIC_TELEMETRY_URL")) != null ? _Ta : (_Sa = base == null ? void 0 : base.telemetry) == null ? void 0 : _Sa.url) != null ? _Ua : process.env.NODE_ENV === "development" ? "http://localhost:3001/api/telemetry" : "https://retrivora.com/api/telemetry"
2608
+ url: (_wb = (_vb = (_tb = readString(env, "TELEMETRY_URL")) != null ? _tb : readString(env, "NEXT_PUBLIC_TELEMETRY_URL")) != null ? _vb : (_ub = base == null ? void 0 : base.telemetry) == null ? void 0 : _ub.url) != null ? _wb : process.env.NODE_ENV === "development" ? "http://localhost:3001/api/telemetry" : "https://retrivora.com/api/telemetry"
2309
2609
  }
2310
2610
  }, readString(env, "GRAPH_DB_PROVIDER") ? {
2311
2611
  graphDb: {
@@ -2792,10 +3092,12 @@ var AnthropicProvider = class {
2792
3092
  var import_axios = __toESM(require("axios"));
2793
3093
  var OllamaProvider = class {
2794
3094
  constructor(llmConfig, embeddingConfig) {
2795
- var _a2, _b;
2796
- const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
3095
+ var _a2, _b, _c;
3096
+ const rawBaseURL = ((_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434").replace(/\/+$/, "");
3097
+ const baseURL = rawBaseURL.replace(/\/(?:api\/v1|v1|api)$/i, "");
2797
3098
  const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
2798
- this.http = import_axios.default.create({ baseURL, timeout });
3099
+ const headers = ((_c = llmConfig.options) == null ? void 0 : _c.headers) || {};
3100
+ this.http = import_axios.default.create({ baseURL, timeout, headers });
2799
3101
  this.llmConfig = llmConfig;
2800
3102
  this.embeddingConfig = embeddingConfig;
2801
3103
  }
@@ -3605,7 +3907,7 @@ var UniversalLLMAdapter = class {
3605
3907
  });
3606
3908
  }
3607
3909
  async chat(messages, context) {
3608
- var _a2, _b;
3910
+ var _a2, _b, _c, _d, _e, _f;
3609
3911
  const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
3610
3912
  const formattedMessages = [
3611
3913
  { role: "system", content: `${this.systemPrompt}
@@ -3630,8 +3932,26 @@ ${context != null ? context : "None"}` },
3630
3932
  temperature: this.temperature
3631
3933
  };
3632
3934
  }
3935
+ const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
3936
+ if (isSelfHost || Boolean(process.env.VERCEL)) {
3937
+ try {
3938
+ const _g2 = globalThis;
3939
+ if (typeof _g2.__retrivoraDispatchChat === "function") {
3940
+ const res = await _g2.__retrivoraDispatchChat({
3941
+ model: this.model,
3942
+ messages: formattedMessages,
3943
+ max_tokens: this.maxTokens,
3944
+ temperature: this.temperature
3945
+ }, this.apiKey);
3946
+ if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
3947
+ return res.response.choices[0].message.content;
3948
+ }
3949
+ }
3950
+ } catch (e) {
3951
+ }
3952
+ }
3633
3953
  const { data } = await this.http.post(path2, payload);
3634
- const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
3954
+ const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
3635
3955
  const result = resolvePath(data, extractPath);
3636
3956
  if (result === void 0) {
3637
3957
  throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
@@ -3645,7 +3965,7 @@ ${context != null ? context : "None"}` },
3645
3965
  */
3646
3966
  chatStream(messages, context) {
3647
3967
  return __asyncGenerator(this, null, function* () {
3648
- var _a2, _b, _c;
3968
+ var _a2, _b, _c, _d, _e, _f, _g2;
3649
3969
  const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
3650
3970
  const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
3651
3971
  const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
@@ -3676,19 +3996,45 @@ ${context != null ? context : "None"}` },
3676
3996
  stream: true
3677
3997
  };
3678
3998
  }
3679
- const response = yield new __await(fetch(url, {
3680
- method: "POST",
3681
- headers: this.resolvedHeaders,
3682
- body: JSON.stringify(payload)
3683
- }));
3684
- if (!response.ok) {
3685
- const errorText = yield new __await(response.text().catch(() => response.statusText));
3686
- throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
3999
+ const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4000
+ let streamBody = null;
4001
+ if (isSelfHost || Boolean(process.env.VERCEL)) {
4002
+ try {
4003
+ const _g3 = globalThis;
4004
+ if (typeof _g3.__retrivoraDispatchChat === "function") {
4005
+ const res = yield new __await(_g3.__retrivoraDispatchChat({
4006
+ model: this.model,
4007
+ messages: formattedMessages,
4008
+ max_tokens: this.maxTokens,
4009
+ temperature: this.temperature,
4010
+ stream: true
4011
+ }, this.apiKey));
4012
+ if (res == null ? void 0 : res.stream) {
4013
+ streamBody = res.stream;
4014
+ } else if ((_f = (_e = (_d = (_c = res == null ? void 0 : res.response) == null ? void 0 : _c.choices) == null ? void 0 : _d[0]) == null ? void 0 : _e.message) == null ? void 0 : _f.content) {
4015
+ yield res.response.choices[0].message.content;
4016
+ return;
4017
+ }
4018
+ }
4019
+ } catch (e) {
4020
+ }
3687
4021
  }
3688
- if (!response.body) {
3689
- throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
4022
+ if (!streamBody) {
4023
+ const response = yield new __await(fetch(url, {
4024
+ method: "POST",
4025
+ headers: this.resolvedHeaders,
4026
+ body: JSON.stringify(payload)
4027
+ }));
4028
+ if (!response.ok) {
4029
+ const errorText = yield new __await(response.text().catch(() => response.statusText));
4030
+ throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
4031
+ }
4032
+ if (!response.body) {
4033
+ throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
4034
+ }
4035
+ streamBody = response.body;
3690
4036
  }
3691
- const reader = response.body.getReader();
4037
+ const reader = streamBody.getReader();
3692
4038
  const decoder = new TextDecoder("utf-8");
3693
4039
  let buffer = "";
3694
4040
  try {
@@ -3697,7 +4043,7 @@ ${context != null ? context : "None"}` },
3697
4043
  if (done) break;
3698
4044
  buffer += decoder.decode(value, { stream: true });
3699
4045
  const lines = buffer.split("\n");
3700
- buffer = (_c = lines.pop()) != null ? _c : "";
4046
+ buffer = (_g2 = lines.pop()) != null ? _g2 : "";
3701
4047
  for (const line of lines) {
3702
4048
  const trimmed = line.trim();
3703
4049
  if (!trimmed || trimmed === "data: [DONE]") continue;
@@ -3725,7 +4071,7 @@ ${context != null ? context : "None"}` },
3725
4071
  });
3726
4072
  }
3727
4073
  async embed(text) {
3728
- var _a2, _b;
4074
+ var _a2, _b, _c, _d;
3729
4075
  const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
3730
4076
  let payload;
3731
4077
  if (this.opts.embedPayloadTemplate) {
@@ -3739,105 +4085,49 @@ ${context != null ? context : "None"}` },
3739
4085
  input: text
3740
4086
  };
3741
4087
  }
4088
+ const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4089
+ if (isSelfHost || Boolean(process.env.VERCEL)) {
4090
+ try {
4091
+ const _g2 = globalThis;
4092
+ if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
4093
+ const res = await _g2.__retrivoraDispatchEmbedding({
4094
+ model: this.model,
4095
+ input: text
4096
+ }, this.apiKey);
4097
+ if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
4098
+ return res.data[0].embedding;
4099
+ }
4100
+ }
4101
+ } catch (e) {
4102
+ }
4103
+ }
3742
4104
  const { data } = await this.http.post(path2, payload);
3743
- const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
4105
+ const extractPath = (_d = this.opts.embedExtractPath) != null ? _d : "data[0].embedding";
3744
4106
  const vector = resolvePath(data, extractPath);
3745
4107
  if (!Array.isArray(vector)) {
3746
4108
  throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
3747
4109
  }
3748
4110
  return vector;
3749
4111
  }
3750
- async batchEmbed(texts) {
3751
- const vectors = [];
3752
- for (const text of texts) {
3753
- vectors.push(await this.embed(text));
3754
- }
3755
- return vectors;
3756
- }
3757
- async ping() {
3758
- try {
3759
- if (this.opts.pingPath) {
3760
- await this.http.get(this.opts.pingPath);
3761
- }
3762
- return true;
3763
- } catch (err) {
3764
- console.error("[UniversalLLMAdapter] Ping failed:", err);
3765
- return false;
3766
- }
3767
- }
3768
- };
3769
-
3770
- // src/exceptions/index.ts
3771
- var RetrivoraError = class extends Error {
3772
- constructor(message, code, details) {
3773
- super(message);
3774
- this.name = new.target.name;
3775
- this.code = code;
3776
- this.details = details;
3777
- }
3778
- };
3779
- var ProviderNotFoundException = class extends RetrivoraError {
3780
- constructor(providerType, provider, details) {
3781
- super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
3782
- }
3783
- };
3784
- var EmbeddingFailedException = class extends RetrivoraError {
3785
- constructor(message = "Embedding generation failed", details) {
3786
- super(message, "EMBEDDING_FAILED", details);
3787
- }
3788
- };
3789
- var RetrievalException = class extends RetrivoraError {
3790
- constructor(message = "Retrieval failed", details) {
3791
- super(message, "RETRIEVAL_FAILED", details);
3792
- }
3793
- };
3794
- var RateLimitException = class extends RetrivoraError {
3795
- constructor(message = "Provider rate limit exceeded", details) {
3796
- super(message, "RATE_LIMITED", details);
3797
- }
3798
- };
3799
- var ConfigurationException = class extends RetrivoraError {
3800
- constructor(message, details) {
3801
- super(message, "CONFIGURATION_ERROR", details);
3802
- }
3803
- };
3804
- var AuthenticationException = class extends RetrivoraError {
3805
- constructor(message = "Provider authentication failed", details) {
3806
- super(message, "AUTHENTICATION_ERROR", details);
3807
- }
3808
- };
3809
- function wrapError(err, defaultCode, defaultMessage) {
3810
- var _a2;
3811
- if (err instanceof RetrivoraError) {
3812
- return err;
3813
- }
3814
- const error = err;
3815
- const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
3816
- const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status);
3817
- const code = error == null ? void 0 : error.code;
3818
- if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
3819
- return new RateLimitException(message, err);
3820
- }
3821
- if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
3822
- return new AuthenticationException(message, err);
4112
+ async batchEmbed(texts) {
4113
+ const vectors = [];
4114
+ for (const text of texts) {
4115
+ vectors.push(await this.embed(text));
4116
+ }
4117
+ return vectors;
3823
4118
  }
3824
- switch (defaultCode) {
3825
- case "PROVIDER_NOT_FOUND":
3826
- return new ProviderNotFoundException("provider", message, err);
3827
- case "EMBEDDING_FAILED":
3828
- return new EmbeddingFailedException(message, err);
3829
- case "RETRIEVAL_FAILED":
3830
- return new RetrievalException(message, err);
3831
- case "RATE_LIMITED":
3832
- return new RateLimitException(message, err);
3833
- case "CONFIGURATION_ERROR":
3834
- return new ConfigurationException(message, err);
3835
- case "AUTHENTICATION_ERROR":
3836
- return new AuthenticationException(message, err);
3837
- default:
3838
- return new RetrivoraError(message, defaultCode, err);
4119
+ async ping() {
4120
+ try {
4121
+ if (this.opts.pingPath) {
4122
+ await this.http.get(this.opts.pingPath);
4123
+ }
4124
+ return true;
4125
+ } catch (err) {
4126
+ console.error("[UniversalLLMAdapter] Ping failed:", err);
4127
+ return false;
4128
+ }
3839
4129
  }
3840
- }
4130
+ };
3841
4131
 
3842
4132
  // src/llm/LLMFactory.ts
3843
4133
  var customProviders = /* @__PURE__ */ new Map();
@@ -8148,8 +8438,11 @@ ${m.content}`).join("\n\n---\n\n");
8148
8438
  fullSources = fullSources.slice(0, topK);
8149
8439
  }
8150
8440
  const rerankMs = performance.now() - rerankStart;
8151
- let context = fullSources.length ? fullSources.map((m, i) => `[Source ${i + 1}]
8152
- ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
8441
+ let context = fullSources.length ? fullSources.map((m, i) => {
8442
+ var _a3;
8443
+ return `[Source ${i + 1}]
8444
+ ${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
8445
+ }).join("\n\n---\n\n") : "No relevant context found.";
8153
8446
  let displayCount = 15;
8154
8447
  if (hasMetadataFilter) {
8155
8448
  displayCount = fullSources.length;
@@ -8233,7 +8526,10 @@ ${context}`;
8233
8526
  if (isSimulatedThinking) {
8234
8527
  finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
8235
8528
  }
8236
- const hardenedHistory = [...history];
8529
+ const hardenedHistory = (Array.isArray(history) ? history : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
8530
+ role: m.role || "user",
8531
+ content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
8532
+ }));
8237
8533
  const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
8238
8534
  const messages = [...hardenedHistory, userQuestion];
8239
8535
  const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
@@ -8380,13 +8676,13 @@ ${context}`;
8380
8676
  rewrittenQuery,
8381
8677
  systemPrompt,
8382
8678
  userPrompt: question + finalRestrictionSuffix,
8383
- chunks: sources.map((s) => {
8384
- var _a3;
8679
+ chunks: (sources || []).filter(Boolean).map((s) => {
8680
+ var _a3, _b2;
8385
8681
  return {
8386
8682
  id: s.id,
8387
8683
  score: s.score,
8388
- content: s.content,
8389
- metadata: (_a3 = s.metadata) != null ? _a3 : {},
8684
+ content: (_a3 = s == null ? void 0 : s.content) != null ? _a3 : "",
8685
+ metadata: (_b2 = s == null ? void 0 : s.metadata) != null ? _b2 : {},
8390
8686
  namespace: ns
8391
8687
  };
8392
8688
  }),
@@ -8764,211 +9060,6 @@ var ProviderHealthCheck = class {
8764
9060
  }
8765
9061
  };
8766
9062
 
8767
- // src/core/LicenseVerifier.ts
8768
- var crypto2 = __toESM(require("crypto"));
8769
- var LicenseVerifier = class {
8770
- /**
8771
- * Decodes, verifies signature, and checks metadata of a license key.
8772
- *
8773
- * @param licenseKey - Base64url signed JWT license key.
8774
- * @param currentProjectId - Project namespace ID.
8775
- * @param publicKeyOverride - Optional override for unit/integration tests.
8776
- */
8777
- static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
8778
- const isProduction = process.env.NODE_ENV === "production";
8779
- const now = Date.now();
8780
- if (licenseKey) {
8781
- const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
8782
- const cached = this.cache.get(cacheKey);
8783
- if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
8784
- const currentTimestampSec = Math.floor(now / 1e3);
8785
- if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
8786
- this.cache.delete(cacheKey);
8787
- } else {
8788
- return cached.payload;
8789
- }
8790
- }
8791
- }
8792
- if (!licenseKey) {
8793
- if (isProduction) {
8794
- throw new ConfigurationException(
8795
- "[Retrivora SDK] License key (licenseKey) is required in production environments."
8796
- );
8797
- }
8798
- console.warn(
8799
- `\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
8800
- );
8801
- return {
8802
- projectId: currentProjectId,
8803
- expiresAt: Math.floor(Date.now() / 1e3) + 86400,
8804
- // Valid for 24h
8805
- tier: "hobby"
8806
- };
8807
- }
8808
- try {
8809
- const parts = licenseKey.split(".");
8810
- if (parts.length !== 3) {
8811
- throw new Error("Malformed token structure (expected 3 parts).");
8812
- }
8813
- const [headerB64, payloadB64, signatureB64] = parts;
8814
- const dataToVerify = `${headerB64}.${payloadB64}`;
8815
- const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
8816
- const signature = Buffer.from(signatureB64, "base64url");
8817
- const data = Buffer.from(dataToVerify);
8818
- const isValid = crypto2.verify(
8819
- "sha256",
8820
- data,
8821
- publicKey,
8822
- signature
8823
- );
8824
- if (!isValid) {
8825
- throw new Error("Signature verification failed.");
8826
- }
8827
- const payload = JSON.parse(
8828
- Buffer.from(payloadB64, "base64url").toString("utf8")
8829
- );
8830
- if (!payload.projectId) {
8831
- throw new Error('License payload is missing "projectId".');
8832
- }
8833
- if (payload.projectId !== currentProjectId) {
8834
- throw new Error(
8835
- `Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
8836
- );
8837
- }
8838
- if (!payload.expiresAt) {
8839
- throw new Error('License payload is missing expiration ("expiresAt").');
8840
- }
8841
- const currentTimestampSec = Math.floor(Date.now() / 1e3);
8842
- if (currentTimestampSec > payload.expiresAt) {
8843
- throw new Error(
8844
- `License key has expired. Expiration: ${new Date(
8845
- payload.expiresAt * 1e3
8846
- ).toDateString()}`
8847
- );
8848
- }
8849
- if (isProduction && provider) {
8850
- const tier = (payload.tier || "").toLowerCase();
8851
- const normalizedProvider = provider.toLowerCase();
8852
- if (tier === "hobby") {
8853
- const allowedHobby = ["postgresql", "pgvector", "supabase"];
8854
- if (!allowedHobby.includes(normalizedProvider)) {
8855
- throw new Error(
8856
- `The database provider "${provider}" is not allowed on the Hobby tier. Hobby tier is restricted to PostgreSQL and Supabase. Please upgrade to a Developer Pro or Enterprise plan.`
8857
- );
8858
- }
8859
- } else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth" || tier === "free_trial" || tier === "free_tier" || tier === "free") {
8860
- const allowedPro = [
8861
- "postgresql",
8862
- "pgvector",
8863
- "supabase",
8864
- "pinecone",
8865
- "qdrant",
8866
- "mongodb",
8867
- "milvus",
8868
- "chroma",
8869
- "chromadb"
8870
- ];
8871
- if (!allowedPro.includes(normalizedProvider)) {
8872
- throw new Error(
8873
- `The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
8874
- );
8875
- }
8876
- }
8877
- }
8878
- if (licenseKey) {
8879
- const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
8880
- this.cache.set(cacheKey, { payload, cachedAt: now });
8881
- }
8882
- return payload;
8883
- } catch (err) {
8884
- const message = err instanceof Error ? err.message : String(err);
8885
- throw new ConfigurationException(
8886
- `[Retrivora SDK] License key validation failed: ${message}`
8887
- );
8888
- }
8889
- }
8890
- static async verifyIP(licenseKey) {
8891
- if (!licenseKey) return;
8892
- try {
8893
- const parts = licenseKey.split(".");
8894
- if (parts.length !== 3) return;
8895
- const [, payloadB64] = parts;
8896
- const payload = JSON.parse(
8897
- Buffer.from(payloadB64, "base64url").toString("utf8")
8898
- );
8899
- const tier = (payload.tier || "").toLowerCase();
8900
- if (tier === "enterprise" || tier === "custom") {
8901
- return;
8902
- }
8903
- if (payload.ipv4 || payload.ipv6) {
8904
- let currentIpv4 = "";
8905
- let currentIpv6 = "";
8906
- try {
8907
- const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
8908
- const data = await res.json();
8909
- currentIpv4 = data.ip;
8910
- } catch (e) {
8911
- }
8912
- try {
8913
- const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
8914
- const data = await res.json();
8915
- currentIpv6 = data.ip;
8916
- } catch (e) {
8917
- }
8918
- const localIps = [];
8919
- try {
8920
- const osModule = require("os");
8921
- const interfaces = osModule.networkInterfaces();
8922
- for (const name of Object.keys(interfaces)) {
8923
- for (const iface of interfaces[name] || []) {
8924
- if (!iface.internal) {
8925
- localIps.push(iface.address);
8926
- }
8927
- }
8928
- }
8929
- } catch (e) {
8930
- }
8931
- const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
8932
- const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
8933
- if (payload.ipv4 && payload.ipv6) {
8934
- if (!isIpv4Match && !isIpv6Match) {
8935
- throw new Error(
8936
- `License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}, IPv6: ${payload.ipv6}) and cannot be used on this machine.`
8937
- );
8938
- }
8939
- } else if (payload.ipv4 && !isIpv4Match) {
8940
- throw new Error(
8941
- `License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
8942
- );
8943
- } else if (payload.ipv6 && !isIpv6Match) {
8944
- throw new Error(
8945
- `License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
8946
- );
8947
- }
8948
- }
8949
- } catch (err) {
8950
- if (err.message.includes("License key access restricted")) {
8951
- throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
8952
- }
8953
- }
8954
- }
8955
- };
8956
- // A simple in-memory cache to save CPU overhead of cryptographic signature checks.
8957
- LicenseVerifier.cache = /* @__PURE__ */ new Map();
8958
- LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
8959
- // Cache verified license for 60 seconds
8960
- // Retrivora's Public Key used to verify the license key signature.
8961
- // In production, this matches the private key held by Retrivora SaaS.
8962
- LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
8963
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
8964
- XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
8965
- xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
8966
- NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
8967
- iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
8968
- +Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
8969
- MwIDAQAB
8970
- -----END PUBLIC KEY-----`;
8971
-
8972
9063
  // src/core/VectorPlugin.ts
8973
9064
  var VectorPlugin = class {
8974
9065
  constructor(hostConfig) {
@@ -9193,6 +9284,7 @@ ${csv.trim()}`);
9193
9284
  // src/core/DatabaseStorage.ts
9194
9285
  var fs = __toESM(require("fs"));
9195
9286
  var path = __toESM(require("path"));
9287
+ var os = __toESM(require("os"));
9196
9288
  var DatabaseStorage = class {
9197
9289
  constructor(config) {
9198
9290
  // Dynamic PG Pool
@@ -9201,7 +9293,8 @@ var DatabaseStorage = class {
9201
9293
  this.mongoClient = null;
9202
9294
  this.mongoDbName = "";
9203
9295
  // Filesystem fallback configuration
9204
- this.fallbackDir = path.join(process.cwd(), ".retrivora");
9296
+ this.isServerless = Boolean(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT);
9297
+ this.fallbackDir = this.isServerless ? path.join(os.tmpdir(), ".retrivora") : path.join(process.cwd(), ".retrivora");
9205
9298
  this.historyFile = path.join(this.fallbackDir, "history.json");
9206
9299
  this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
9207
9300
  var _a2, _b, _c, _d, _e;
@@ -9331,10 +9424,27 @@ var DatabaseStorage = class {
9331
9424
  }
9332
9425
  // Helper for FS fallback writes
9333
9426
  writeLocalFile(filePath, data) {
9334
- if (!fs.existsSync(this.fallbackDir)) {
9335
- fs.mkdirSync(this.fallbackDir, { recursive: true });
9427
+ try {
9428
+ const dir = path.dirname(filePath);
9429
+ if (!fs.existsSync(dir)) {
9430
+ fs.mkdirSync(dir, { recursive: true });
9431
+ }
9432
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
9433
+ } catch (err) {
9434
+ if (err.code === "EROFS") {
9435
+ try {
9436
+ const tmpDir = path.join(os.tmpdir(), ".retrivora");
9437
+ if (!fs.existsSync(tmpDir)) {
9438
+ fs.mkdirSync(tmpDir, { recursive: true });
9439
+ }
9440
+ const tmpFilePath = path.join(tmpDir, path.basename(filePath));
9441
+ fs.writeFileSync(tmpFilePath, JSON.stringify(data, null, 2), "utf-8");
9442
+ } catch (e) {
9443
+ }
9444
+ } else {
9445
+ console.warn(`[DatabaseStorage] Failed to write local fallback file: ${err.message}`);
9446
+ }
9336
9447
  }
9337
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
9338
9448
  }
9339
9449
  // ─── Message History Operations ──────────────────────────────────────────
9340
9450
  async saveMessage(sessionId, message) {
@@ -9766,7 +9876,17 @@ function createChatHandler(configOrPlugin, options) {
9766
9876
  if (rateLimited) return rateLimited;
9767
9877
  try {
9768
9878
  const body = await req.json();
9769
- const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
9879
+ const bodyObj = body != null ? body : {};
9880
+ let rawMessage = bodyObj.message;
9881
+ if (!rawMessage && Array.isArray(bodyObj.messages) && bodyObj.messages.length > 0) {
9882
+ const lastMsg = bodyObj.messages[bodyObj.messages.length - 1];
9883
+ rawMessage = typeof lastMsg === "string" ? lastMsg : (lastMsg == null ? void 0 : lastMsg.content) || (lastMsg == null ? void 0 : lastMsg.text);
9884
+ }
9885
+ if (!rawMessage && typeof bodyObj.prompt === "string") {
9886
+ rawMessage = bodyObj.prompt;
9887
+ }
9888
+ const history = bodyObj.history || (Array.isArray(bodyObj.messages) ? bodyObj.messages.slice(0, -1) : []);
9889
+ const { namespace, sessionId = "default", messageId, userMessageId } = bodyObj;
9770
9890
  const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
9771
9891
  if (!sanitized.ok) {
9772
9892
  return import_server.NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
@@ -9818,7 +9938,17 @@ function createStreamHandler(configOrPlugin, options) {
9818
9938
  headers: { "Content-Type": "application/json" }
9819
9939
  });
9820
9940
  }
9821
- const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
9941
+ const bodyObj = body != null ? body : {};
9942
+ let rawMessage = bodyObj.message;
9943
+ if (!rawMessage && Array.isArray(bodyObj.messages) && bodyObj.messages.length > 0) {
9944
+ const lastMsg = bodyObj.messages[bodyObj.messages.length - 1];
9945
+ rawMessage = typeof lastMsg === "string" ? lastMsg : (lastMsg == null ? void 0 : lastMsg.content) || (lastMsg == null ? void 0 : lastMsg.text);
9946
+ }
9947
+ if (!rawMessage && typeof bodyObj.prompt === "string") {
9948
+ rawMessage = bodyObj.prompt;
9949
+ }
9950
+ const history = bodyObj.history || (Array.isArray(bodyObj.messages) ? bodyObj.messages.slice(0, -1) : []);
9951
+ const { namespace, sessionId = "default", messageId, userMessageId } = bodyObj;
9822
9952
  const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
9823
9953
  if (!sanitized.ok) {
9824
9954
  return new Response(