@retrivora-ai/rag-engine 2.1.9 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -793,6 +793,84 @@ var init_BaseVectorProvider = __esm({
793
793
  }
794
794
  });
795
795
 
796
+ // src/core/ConfigFetcher.ts
797
+ var ConfigFetcher;
798
+ var init_ConfigFetcher = __esm({
799
+ "src/core/ConfigFetcher.ts"() {
800
+ "use strict";
801
+ ConfigFetcher = class {
802
+ // 5-minute in-memory session cache
803
+ /**
804
+ * Fetch full project configuration (vectorDb + embedding + llm) from Retrivora Control Plane.
805
+ */
806
+ static async fetchRemoteConfig(projectId, licenseKey) {
807
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
808
+ const cacheKey = `${projectId}:${licenseKey || ""}`;
809
+ const now = Date.now();
810
+ const cached = this.cache.get(cacheKey);
811
+ if (cached && now - cached.cachedAt < this.TTL_MS) {
812
+ return cached.config;
813
+ }
814
+ const controlPlaneUrls = [
815
+ process.env.RETRIVORA_CONTROL_PLANE_URL,
816
+ process.env.NEXT_PUBLIC_RETRIVORA_CONTROL_PLANE_URL,
817
+ "https://retrivora.com",
818
+ "http://localhost:3000"
819
+ ].filter(Boolean);
820
+ for (const baseUrl of controlPlaneUrls) {
821
+ try {
822
+ const url = `${baseUrl.replace(/\/$/, "")}/api/v1/config?projectId=${encodeURIComponent(projectId)}${licenseKey ? `&licenseKey=${encodeURIComponent(licenseKey)}` : ""}`;
823
+ const res = await fetch(url, {
824
+ method: "GET",
825
+ headers: __spreadValues({
826
+ "Content-Type": "application/json"
827
+ }, licenseKey ? { "x-license-key": licenseKey } : {})
828
+ });
829
+ if (res.ok) {
830
+ const data = await res.json();
831
+ if ((data == null ? void 0 : data.success) && ((_a2 = data == null ? void 0 : data.vectorDb) == null ? void 0 : _a2.apiKey)) {
832
+ const config = {
833
+ vectorDb: {
834
+ apiKey: data.vectorDb.apiKey,
835
+ indexName: data.vectorDb.indexName || "retrivora-free",
836
+ provider: data.vectorDb.provider || "pinecone"
837
+ },
838
+ embedding: {
839
+ provider: ((_b = data.embedding) == null ? void 0 : _b.provider) || "universal_rest",
840
+ model: ((_c = data.embedding) == null ? void 0 : _c.model) || "text-embedding-004",
841
+ baseUrl: ((_d = data.embedding) == null ? void 0 : _d.baseUrl) || "https://llm.retrivora.com/api/v1",
842
+ apiKey: ((_e = data.embedding) == null ? void 0 : _e.apiKey) || licenseKey || "",
843
+ profile: ((_f = data.embedding) == null ? void 0 : _f.profile) || "litellm"
844
+ },
845
+ llm: {
846
+ provider: ((_g2 = data.llm) == null ? void 0 : _g2.provider) || "universal_rest",
847
+ model: ((_h = data.llm) == null ? void 0 : _h.model) || "llama-3.1-8b-instant",
848
+ baseUrl: ((_i = data.llm) == null ? void 0 : _i.baseUrl) || "https://llm.retrivora.com/api/v1",
849
+ apiKey: ((_j = data.llm) == null ? void 0 : _j.apiKey) || licenseKey || "",
850
+ profile: ((_k = data.llm) == null ? void 0 : _k.profile) || "litellm"
851
+ }
852
+ };
853
+ this.cache.set(cacheKey, { config, cachedAt: now });
854
+ return config;
855
+ }
856
+ }
857
+ } catch (e) {
858
+ }
859
+ }
860
+ return null;
861
+ }
862
+ /** Convenience: fetch only vector DB config (backwards compat). */
863
+ static async fetchRemoteVectorConfig(projectId, licenseKey) {
864
+ var _a2;
865
+ const config = await this.fetchRemoteConfig(projectId, licenseKey);
866
+ return (_a2 = config == null ? void 0 : config.vectorDb) != null ? _a2 : null;
867
+ }
868
+ };
869
+ ConfigFetcher.cache = /* @__PURE__ */ new Map();
870
+ ConfigFetcher.TTL_MS = 5 * 60 * 1e3;
871
+ }
872
+ });
873
+
796
874
  // src/providers/vectordb/PineconeProvider.ts
797
875
  var PineconeProvider_exports = {};
798
876
  __export(PineconeProvider_exports, {
@@ -804,6 +882,7 @@ var init_PineconeProvider = __esm({
804
882
  "use strict";
805
883
  import_pinecone = require("@pinecone-database/pinecone");
806
884
  init_BaseVectorProvider();
885
+ init_ConfigFetcher();
807
886
  PineconeProvider = class extends BaseVectorProvider {
808
887
  constructor(config) {
809
888
  super(config);
@@ -869,27 +948,49 @@ var init_PineconeProvider = __esm({
869
948
  }
870
949
  async initialize() {
871
950
  var _a2, _b;
872
- const key = this.apiKey || process.env.PINECONE_API_KEY || "";
951
+ if (this.client) return;
952
+ let key = this.apiKey || process.env.PINECONE_API_KEY || "";
953
+ if (!key) {
954
+ const projectId = process.env.RAG_PROJECT_ID || process.env.NEXT_PUBLIC_RAG_PROJECT_ID || "my-rag-app";
955
+ const licenseKey = process.env.RETRIVORA_LICENSE_KEY || process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY;
956
+ const remoteConfig = await ConfigFetcher.fetchRemoteVectorConfig(projectId, licenseKey);
957
+ if (remoteConfig == null ? void 0 : remoteConfig.apiKey) {
958
+ key = remoteConfig.apiKey;
959
+ this.apiKey = key;
960
+ if (remoteConfig.indexName) {
961
+ this.indexName = remoteConfig.indexName;
962
+ }
963
+ }
964
+ }
873
965
  if (!key) {
874
- console.log("[PineconeProvider] Keyless Mode active \u2014 Vector operations managed via Retrivora Cloud Gateway.");
966
+ console.warn("[PineconeProvider] Warning: No Pinecone API key available locally or remotely.");
875
967
  return;
876
968
  }
877
969
  this.client = new import_pinecone.Pinecone({ apiKey: key });
878
- const indexes = await this.client.listIndexes();
879
- const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
880
- if (!names.includes(this.indexName)) {
881
- throw new Error(
882
- `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
883
- );
970
+ try {
971
+ const indexes = await this.client.listIndexes();
972
+ const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
973
+ if (!names.includes(this.indexName)) {
974
+ console.warn(`[PineconeProvider] Target index "${this.indexName}" not listed. Proceeding with configured index name.`);
975
+ }
976
+ } catch (err) {
977
+ console.warn("[PineconeProvider] List index verification warning:", err instanceof Error ? err.message : String(err));
884
978
  }
885
979
  }
886
- index(namespace) {
980
+ async getActiveIndex(namespace) {
981
+ if (!this.client) {
982
+ await this.initialize();
983
+ }
984
+ if (!this.client) {
985
+ throw new Error("[PineconeProvider] Cannot execute vector operation: Pinecone client failed to initialize.");
986
+ }
887
987
  const idx = this.client.index(this.indexName);
888
988
  return namespace ? idx.namespace(namespace) : idx.namespace("");
889
989
  }
890
990
  async upsert(doc, namespace) {
891
991
  var _a2;
892
- await this.index(namespace).upsert({
992
+ const targetIdx = await this.getActiveIndex(namespace);
993
+ await targetIdx.upsert({
893
994
  records: [{
894
995
  id: String(doc.id),
895
996
  values: doc.vector,
@@ -898,6 +999,7 @@ var init_PineconeProvider = __esm({
898
999
  });
899
1000
  }
900
1001
  async batchUpsert(docs, namespace) {
1002
+ const targetIdx = await this.getActiveIndex(namespace);
901
1003
  const BATCH = 100;
902
1004
  for (let i = 0; i < docs.length; i += BATCH) {
903
1005
  const records = docs.slice(i, i + BATCH).map((d) => {
@@ -908,13 +1010,14 @@ var init_PineconeProvider = __esm({
908
1010
  metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
909
1011
  };
910
1012
  });
911
- await this.index(namespace).upsert({ records });
1013
+ await targetIdx.upsert({ records });
912
1014
  }
913
1015
  }
914
1016
  async query(vector, topK, namespace, filter) {
915
1017
  var _a2;
1018
+ const targetIdx = await this.getActiveIndex(namespace);
916
1019
  const pineconeFilter = this.sanitizeFilter(filter);
917
- const result = await this.index(namespace).query(__spreadValues({
1020
+ const result = await targetIdx.query(__spreadValues({
918
1021
  vector,
919
1022
  topK,
920
1023
  includeMetadata: true
@@ -930,13 +1033,17 @@ var init_PineconeProvider = __esm({
930
1033
  });
931
1034
  }
932
1035
  async delete(id, namespace) {
933
- await this.index(namespace).deleteOne({ id: String(id) });
1036
+ const targetIdx = await this.getActiveIndex(namespace);
1037
+ await targetIdx.deleteOne({ id: String(id) });
934
1038
  }
935
1039
  async deleteNamespace(namespace) {
936
- await this.client.index(this.indexName).namespace(namespace).deleteAll();
1040
+ const targetIdx = await this.getActiveIndex(namespace);
1041
+ await targetIdx.deleteAll();
937
1042
  }
938
1043
  async ping() {
939
1044
  try {
1045
+ if (!this.client) await this.initialize();
1046
+ if (!this.client) return false;
940
1047
  await this.client.listIndexes();
941
1048
  return true;
942
1049
  } catch (e) {
@@ -3167,7 +3274,7 @@ function getEnvConfig(env = process.env, base) {
3167
3274
  return true;
3168
3275
  }
3169
3276
  })();
3170
- const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://llm.retrivora.com/api/v1";
3277
+ const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://retrivora.com/api/v1";
3171
3278
  const defaultLlmProvider = isFreeTier ? "universal_rest" : "universal_rest";
3172
3279
  const llmProvider = (_sa = (_ra = readEnum(env, "LLM_PROVIDER", defaultLlmProvider, LLM_PROVIDERS)) != null ? _ra : (_qa = base == null ? void 0 : base.llm) == null ? void 0 : _qa.provider) != null ? _sa : defaultLlmProvider;
3173
3280
  const llmBaseUrl = (_wa = (_va = (_ta = readString(env, "LITELLM_BASE_URL")) != null ? _ta : readString(env, "LLM_BASE_URL")) != null ? _va : (_ua = base == null ? void 0 : base.llm) == null ? void 0 : _ua.baseUrl) != null ? _wa : defaultGatewayUrl;
@@ -778,6 +778,84 @@ var init_BaseVectorProvider = __esm({
778
778
  }
779
779
  });
780
780
 
781
+ // src/core/ConfigFetcher.ts
782
+ var ConfigFetcher;
783
+ var init_ConfigFetcher = __esm({
784
+ "src/core/ConfigFetcher.ts"() {
785
+ "use strict";
786
+ ConfigFetcher = class {
787
+ // 5-minute in-memory session cache
788
+ /**
789
+ * Fetch full project configuration (vectorDb + embedding + llm) from Retrivora Control Plane.
790
+ */
791
+ static async fetchRemoteConfig(projectId, licenseKey) {
792
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
793
+ const cacheKey = `${projectId}:${licenseKey || ""}`;
794
+ const now = Date.now();
795
+ const cached = this.cache.get(cacheKey);
796
+ if (cached && now - cached.cachedAt < this.TTL_MS) {
797
+ return cached.config;
798
+ }
799
+ const controlPlaneUrls = [
800
+ process.env.RETRIVORA_CONTROL_PLANE_URL,
801
+ process.env.NEXT_PUBLIC_RETRIVORA_CONTROL_PLANE_URL,
802
+ "https://retrivora.com",
803
+ "http://localhost:3000"
804
+ ].filter(Boolean);
805
+ for (const baseUrl of controlPlaneUrls) {
806
+ try {
807
+ const url = `${baseUrl.replace(/\/$/, "")}/api/v1/config?projectId=${encodeURIComponent(projectId)}${licenseKey ? `&licenseKey=${encodeURIComponent(licenseKey)}` : ""}`;
808
+ const res = await fetch(url, {
809
+ method: "GET",
810
+ headers: __spreadValues({
811
+ "Content-Type": "application/json"
812
+ }, licenseKey ? { "x-license-key": licenseKey } : {})
813
+ });
814
+ if (res.ok) {
815
+ const data = await res.json();
816
+ if ((data == null ? void 0 : data.success) && ((_a2 = data == null ? void 0 : data.vectorDb) == null ? void 0 : _a2.apiKey)) {
817
+ const config = {
818
+ vectorDb: {
819
+ apiKey: data.vectorDb.apiKey,
820
+ indexName: data.vectorDb.indexName || "retrivora-free",
821
+ provider: data.vectorDb.provider || "pinecone"
822
+ },
823
+ embedding: {
824
+ provider: ((_b = data.embedding) == null ? void 0 : _b.provider) || "universal_rest",
825
+ model: ((_c = data.embedding) == null ? void 0 : _c.model) || "text-embedding-004",
826
+ baseUrl: ((_d = data.embedding) == null ? void 0 : _d.baseUrl) || "https://llm.retrivora.com/api/v1",
827
+ apiKey: ((_e = data.embedding) == null ? void 0 : _e.apiKey) || licenseKey || "",
828
+ profile: ((_f = data.embedding) == null ? void 0 : _f.profile) || "litellm"
829
+ },
830
+ llm: {
831
+ provider: ((_g2 = data.llm) == null ? void 0 : _g2.provider) || "universal_rest",
832
+ model: ((_h = data.llm) == null ? void 0 : _h.model) || "llama-3.1-8b-instant",
833
+ baseUrl: ((_i = data.llm) == null ? void 0 : _i.baseUrl) || "https://llm.retrivora.com/api/v1",
834
+ apiKey: ((_j = data.llm) == null ? void 0 : _j.apiKey) || licenseKey || "",
835
+ profile: ((_k = data.llm) == null ? void 0 : _k.profile) || "litellm"
836
+ }
837
+ };
838
+ this.cache.set(cacheKey, { config, cachedAt: now });
839
+ return config;
840
+ }
841
+ }
842
+ } catch (e) {
843
+ }
844
+ }
845
+ return null;
846
+ }
847
+ /** Convenience: fetch only vector DB config (backwards compat). */
848
+ static async fetchRemoteVectorConfig(projectId, licenseKey) {
849
+ var _a2;
850
+ const config = await this.fetchRemoteConfig(projectId, licenseKey);
851
+ return (_a2 = config == null ? void 0 : config.vectorDb) != null ? _a2 : null;
852
+ }
853
+ };
854
+ ConfigFetcher.cache = /* @__PURE__ */ new Map();
855
+ ConfigFetcher.TTL_MS = 5 * 60 * 1e3;
856
+ }
857
+ });
858
+
781
859
  // src/providers/vectordb/PineconeProvider.ts
782
860
  var PineconeProvider_exports = {};
783
861
  __export(PineconeProvider_exports, {
@@ -789,6 +867,7 @@ var init_PineconeProvider = __esm({
789
867
  "src/providers/vectordb/PineconeProvider.ts"() {
790
868
  "use strict";
791
869
  init_BaseVectorProvider();
870
+ init_ConfigFetcher();
792
871
  PineconeProvider = class extends BaseVectorProvider {
793
872
  constructor(config) {
794
873
  super(config);
@@ -854,27 +933,49 @@ var init_PineconeProvider = __esm({
854
933
  }
855
934
  async initialize() {
856
935
  var _a2, _b;
857
- const key = this.apiKey || process.env.PINECONE_API_KEY || "";
936
+ if (this.client) return;
937
+ let key = this.apiKey || process.env.PINECONE_API_KEY || "";
938
+ if (!key) {
939
+ const projectId = process.env.RAG_PROJECT_ID || process.env.NEXT_PUBLIC_RAG_PROJECT_ID || "my-rag-app";
940
+ const licenseKey = process.env.RETRIVORA_LICENSE_KEY || process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY;
941
+ const remoteConfig = await ConfigFetcher.fetchRemoteVectorConfig(projectId, licenseKey);
942
+ if (remoteConfig == null ? void 0 : remoteConfig.apiKey) {
943
+ key = remoteConfig.apiKey;
944
+ this.apiKey = key;
945
+ if (remoteConfig.indexName) {
946
+ this.indexName = remoteConfig.indexName;
947
+ }
948
+ }
949
+ }
858
950
  if (!key) {
859
- console.log("[PineconeProvider] Keyless Mode active \u2014 Vector operations managed via Retrivora Cloud Gateway.");
951
+ console.warn("[PineconeProvider] Warning: No Pinecone API key available locally or remotely.");
860
952
  return;
861
953
  }
862
954
  this.client = new Pinecone({ apiKey: key });
863
- const indexes = await this.client.listIndexes();
864
- const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
865
- if (!names.includes(this.indexName)) {
866
- throw new Error(
867
- `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
868
- );
955
+ try {
956
+ const indexes = await this.client.listIndexes();
957
+ const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
958
+ if (!names.includes(this.indexName)) {
959
+ console.warn(`[PineconeProvider] Target index "${this.indexName}" not listed. Proceeding with configured index name.`);
960
+ }
961
+ } catch (err) {
962
+ console.warn("[PineconeProvider] List index verification warning:", err instanceof Error ? err.message : String(err));
869
963
  }
870
964
  }
871
- index(namespace) {
965
+ async getActiveIndex(namespace) {
966
+ if (!this.client) {
967
+ await this.initialize();
968
+ }
969
+ if (!this.client) {
970
+ throw new Error("[PineconeProvider] Cannot execute vector operation: Pinecone client failed to initialize.");
971
+ }
872
972
  const idx = this.client.index(this.indexName);
873
973
  return namespace ? idx.namespace(namespace) : idx.namespace("");
874
974
  }
875
975
  async upsert(doc, namespace) {
876
976
  var _a2;
877
- await this.index(namespace).upsert({
977
+ const targetIdx = await this.getActiveIndex(namespace);
978
+ await targetIdx.upsert({
878
979
  records: [{
879
980
  id: String(doc.id),
880
981
  values: doc.vector,
@@ -883,6 +984,7 @@ var init_PineconeProvider = __esm({
883
984
  });
884
985
  }
885
986
  async batchUpsert(docs, namespace) {
987
+ const targetIdx = await this.getActiveIndex(namespace);
886
988
  const BATCH = 100;
887
989
  for (let i = 0; i < docs.length; i += BATCH) {
888
990
  const records = docs.slice(i, i + BATCH).map((d) => {
@@ -893,13 +995,14 @@ var init_PineconeProvider = __esm({
893
995
  metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
894
996
  };
895
997
  });
896
- await this.index(namespace).upsert({ records });
998
+ await targetIdx.upsert({ records });
897
999
  }
898
1000
  }
899
1001
  async query(vector, topK, namespace, filter) {
900
1002
  var _a2;
1003
+ const targetIdx = await this.getActiveIndex(namespace);
901
1004
  const pineconeFilter = this.sanitizeFilter(filter);
902
- const result = await this.index(namespace).query(__spreadValues({
1005
+ const result = await targetIdx.query(__spreadValues({
903
1006
  vector,
904
1007
  topK,
905
1008
  includeMetadata: true
@@ -915,13 +1018,17 @@ var init_PineconeProvider = __esm({
915
1018
  });
916
1019
  }
917
1020
  async delete(id, namespace) {
918
- await this.index(namespace).deleteOne({ id: String(id) });
1021
+ const targetIdx = await this.getActiveIndex(namespace);
1022
+ await targetIdx.deleteOne({ id: String(id) });
919
1023
  }
920
1024
  async deleteNamespace(namespace) {
921
- await this.client.index(this.indexName).namespace(namespace).deleteAll();
1025
+ const targetIdx = await this.getActiveIndex(namespace);
1026
+ await targetIdx.deleteAll();
922
1027
  }
923
1028
  async ping() {
924
1029
  try {
1030
+ if (!this.client) await this.initialize();
1031
+ if (!this.client) return false;
925
1032
  await this.client.listIndexes();
926
1033
  return true;
927
1034
  } catch (e) {
@@ -3132,7 +3239,7 @@ function getEnvConfig(env = process.env, base) {
3132
3239
  return true;
3133
3240
  }
3134
3241
  })();
3135
- const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://llm.retrivora.com/api/v1";
3242
+ const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://retrivora.com/api/v1";
3136
3243
  const defaultLlmProvider = isFreeTier ? "universal_rest" : "universal_rest";
3137
3244
  const llmProvider = (_sa = (_ra = readEnum(env, "LLM_PROVIDER", defaultLlmProvider, LLM_PROVIDERS)) != null ? _ra : (_qa = base == null ? void 0 : base.llm) == null ? void 0 : _qa.provider) != null ? _sa : defaultLlmProvider;
3138
3245
  const llmBaseUrl = (_wa = (_va = (_ta = readString(env, "LITELLM_BASE_URL")) != null ? _ta : readString(env, "LLM_BASE_URL")) != null ? _va : (_ua = base == null ? void 0 : base.llm) == null ? void 0 : _ua.baseUrl) != null ? _wa : defaultGatewayUrl;
package/dist/server.d.mts CHANGED
@@ -198,7 +198,7 @@ declare class ConfigResolver {
198
198
  */
199
199
  declare abstract class BaseVectorProvider {
200
200
  protected readonly config: VectorDBConfig;
201
- protected readonly indexName: string;
201
+ protected indexName: string;
202
202
  constructor(config: VectorDBConfig);
203
203
  /**
204
204
  * Initialise the connection (create tables, verify index, etc.)
@@ -615,12 +615,12 @@ declare class DocumentParser {
615
615
  */
616
616
  declare class PineconeProvider extends BaseVectorProvider {
617
617
  private client;
618
- private readonly apiKey;
618
+ private apiKey;
619
619
  constructor(config: VectorDBConfig);
620
620
  static getValidator(): IProviderValidator;
621
621
  static getHealthChecker(): IProviderHealthChecker;
622
622
  initialize(): Promise<void>;
623
- private index;
623
+ private getActiveIndex;
624
624
  upsert(doc: UpsertDocument, namespace?: string): Promise<void>;
625
625
  batchUpsert(docs: UpsertDocument[], namespace?: string): Promise<void>;
626
626
  query(vector: number[], topK: number, namespace?: string, filter?: Record<string, unknown>): Promise<VectorMatch[]>;
package/dist/server.d.ts CHANGED
@@ -198,7 +198,7 @@ declare class ConfigResolver {
198
198
  */
199
199
  declare abstract class BaseVectorProvider {
200
200
  protected readonly config: VectorDBConfig;
201
- protected readonly indexName: string;
201
+ protected indexName: string;
202
202
  constructor(config: VectorDBConfig);
203
203
  /**
204
204
  * Initialise the connection (create tables, verify index, etc.)
@@ -615,12 +615,12 @@ declare class DocumentParser {
615
615
  */
616
616
  declare class PineconeProvider extends BaseVectorProvider {
617
617
  private client;
618
- private readonly apiKey;
618
+ private apiKey;
619
619
  constructor(config: VectorDBConfig);
620
620
  static getValidator(): IProviderValidator;
621
621
  static getHealthChecker(): IProviderHealthChecker;
622
622
  initialize(): Promise<void>;
623
- private index;
623
+ private getActiveIndex;
624
624
  upsert(doc: UpsertDocument, namespace?: string): Promise<void>;
625
625
  batchUpsert(docs: UpsertDocument[], namespace?: string): Promise<void>;
626
626
  query(vector: number[], topK: number, namespace?: string, filter?: Record<string, unknown>): Promise<VectorMatch[]>;
package/dist/server.js CHANGED
@@ -793,6 +793,84 @@ var init_BaseVectorProvider = __esm({
793
793
  }
794
794
  });
795
795
 
796
+ // src/core/ConfigFetcher.ts
797
+ var ConfigFetcher;
798
+ var init_ConfigFetcher = __esm({
799
+ "src/core/ConfigFetcher.ts"() {
800
+ "use strict";
801
+ ConfigFetcher = class {
802
+ // 5-minute in-memory session cache
803
+ /**
804
+ * Fetch full project configuration (vectorDb + embedding + llm) from Retrivora Control Plane.
805
+ */
806
+ static async fetchRemoteConfig(projectId, licenseKey) {
807
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
808
+ const cacheKey = `${projectId}:${licenseKey || ""}`;
809
+ const now = Date.now();
810
+ const cached = this.cache.get(cacheKey);
811
+ if (cached && now - cached.cachedAt < this.TTL_MS) {
812
+ return cached.config;
813
+ }
814
+ const controlPlaneUrls = [
815
+ process.env.RETRIVORA_CONTROL_PLANE_URL,
816
+ process.env.NEXT_PUBLIC_RETRIVORA_CONTROL_PLANE_URL,
817
+ "https://retrivora.com",
818
+ "http://localhost:3000"
819
+ ].filter(Boolean);
820
+ for (const baseUrl of controlPlaneUrls) {
821
+ try {
822
+ const url = `${baseUrl.replace(/\/$/, "")}/api/v1/config?projectId=${encodeURIComponent(projectId)}${licenseKey ? `&licenseKey=${encodeURIComponent(licenseKey)}` : ""}`;
823
+ const res = await fetch(url, {
824
+ method: "GET",
825
+ headers: __spreadValues({
826
+ "Content-Type": "application/json"
827
+ }, licenseKey ? { "x-license-key": licenseKey } : {})
828
+ });
829
+ if (res.ok) {
830
+ const data = await res.json();
831
+ if ((data == null ? void 0 : data.success) && ((_a2 = data == null ? void 0 : data.vectorDb) == null ? void 0 : _a2.apiKey)) {
832
+ const config = {
833
+ vectorDb: {
834
+ apiKey: data.vectorDb.apiKey,
835
+ indexName: data.vectorDb.indexName || "retrivora-free",
836
+ provider: data.vectorDb.provider || "pinecone"
837
+ },
838
+ embedding: {
839
+ provider: ((_b = data.embedding) == null ? void 0 : _b.provider) || "universal_rest",
840
+ model: ((_c = data.embedding) == null ? void 0 : _c.model) || "text-embedding-004",
841
+ baseUrl: ((_d = data.embedding) == null ? void 0 : _d.baseUrl) || "https://llm.retrivora.com/api/v1",
842
+ apiKey: ((_e = data.embedding) == null ? void 0 : _e.apiKey) || licenseKey || "",
843
+ profile: ((_f = data.embedding) == null ? void 0 : _f.profile) || "litellm"
844
+ },
845
+ llm: {
846
+ provider: ((_g2 = data.llm) == null ? void 0 : _g2.provider) || "universal_rest",
847
+ model: ((_h = data.llm) == null ? void 0 : _h.model) || "llama-3.1-8b-instant",
848
+ baseUrl: ((_i = data.llm) == null ? void 0 : _i.baseUrl) || "https://llm.retrivora.com/api/v1",
849
+ apiKey: ((_j = data.llm) == null ? void 0 : _j.apiKey) || licenseKey || "",
850
+ profile: ((_k = data.llm) == null ? void 0 : _k.profile) || "litellm"
851
+ }
852
+ };
853
+ this.cache.set(cacheKey, { config, cachedAt: now });
854
+ return config;
855
+ }
856
+ }
857
+ } catch (e) {
858
+ }
859
+ }
860
+ return null;
861
+ }
862
+ /** Convenience: fetch only vector DB config (backwards compat). */
863
+ static async fetchRemoteVectorConfig(projectId, licenseKey) {
864
+ var _a2;
865
+ const config = await this.fetchRemoteConfig(projectId, licenseKey);
866
+ return (_a2 = config == null ? void 0 : config.vectorDb) != null ? _a2 : null;
867
+ }
868
+ };
869
+ ConfigFetcher.cache = /* @__PURE__ */ new Map();
870
+ ConfigFetcher.TTL_MS = 5 * 60 * 1e3;
871
+ }
872
+ });
873
+
796
874
  // src/providers/vectordb/PineconeProvider.ts
797
875
  var PineconeProvider_exports = {};
798
876
  __export(PineconeProvider_exports, {
@@ -804,6 +882,7 @@ var init_PineconeProvider = __esm({
804
882
  "use strict";
805
883
  import_pinecone = require("@pinecone-database/pinecone");
806
884
  init_BaseVectorProvider();
885
+ init_ConfigFetcher();
807
886
  PineconeProvider = class extends BaseVectorProvider {
808
887
  constructor(config) {
809
888
  super(config);
@@ -869,27 +948,49 @@ var init_PineconeProvider = __esm({
869
948
  }
870
949
  async initialize() {
871
950
  var _a2, _b;
872
- const key = this.apiKey || process.env.PINECONE_API_KEY || "";
951
+ if (this.client) return;
952
+ let key = this.apiKey || process.env.PINECONE_API_KEY || "";
953
+ if (!key) {
954
+ const projectId = process.env.RAG_PROJECT_ID || process.env.NEXT_PUBLIC_RAG_PROJECT_ID || "my-rag-app";
955
+ const licenseKey = process.env.RETRIVORA_LICENSE_KEY || process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY;
956
+ const remoteConfig = await ConfigFetcher.fetchRemoteVectorConfig(projectId, licenseKey);
957
+ if (remoteConfig == null ? void 0 : remoteConfig.apiKey) {
958
+ key = remoteConfig.apiKey;
959
+ this.apiKey = key;
960
+ if (remoteConfig.indexName) {
961
+ this.indexName = remoteConfig.indexName;
962
+ }
963
+ }
964
+ }
873
965
  if (!key) {
874
- console.log("[PineconeProvider] Keyless Mode active \u2014 Vector operations managed via Retrivora Cloud Gateway.");
966
+ console.warn("[PineconeProvider] Warning: No Pinecone API key available locally or remotely.");
875
967
  return;
876
968
  }
877
969
  this.client = new import_pinecone.Pinecone({ apiKey: key });
878
- const indexes = await this.client.listIndexes();
879
- const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
880
- if (!names.includes(this.indexName)) {
881
- throw new Error(
882
- `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
883
- );
970
+ try {
971
+ const indexes = await this.client.listIndexes();
972
+ const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
973
+ if (!names.includes(this.indexName)) {
974
+ console.warn(`[PineconeProvider] Target index "${this.indexName}" not listed. Proceeding with configured index name.`);
975
+ }
976
+ } catch (err) {
977
+ console.warn("[PineconeProvider] List index verification warning:", err instanceof Error ? err.message : String(err));
884
978
  }
885
979
  }
886
- index(namespace) {
980
+ async getActiveIndex(namespace) {
981
+ if (!this.client) {
982
+ await this.initialize();
983
+ }
984
+ if (!this.client) {
985
+ throw new Error("[PineconeProvider] Cannot execute vector operation: Pinecone client failed to initialize.");
986
+ }
887
987
  const idx = this.client.index(this.indexName);
888
988
  return namespace ? idx.namespace(namespace) : idx.namespace("");
889
989
  }
890
990
  async upsert(doc, namespace) {
891
991
  var _a2;
892
- await this.index(namespace).upsert({
992
+ const targetIdx = await this.getActiveIndex(namespace);
993
+ await targetIdx.upsert({
893
994
  records: [{
894
995
  id: String(doc.id),
895
996
  values: doc.vector,
@@ -898,6 +999,7 @@ var init_PineconeProvider = __esm({
898
999
  });
899
1000
  }
900
1001
  async batchUpsert(docs, namespace) {
1002
+ const targetIdx = await this.getActiveIndex(namespace);
901
1003
  const BATCH = 100;
902
1004
  for (let i = 0; i < docs.length; i += BATCH) {
903
1005
  const records = docs.slice(i, i + BATCH).map((d) => {
@@ -908,13 +1010,14 @@ var init_PineconeProvider = __esm({
908
1010
  metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
909
1011
  };
910
1012
  });
911
- await this.index(namespace).upsert({ records });
1013
+ await targetIdx.upsert({ records });
912
1014
  }
913
1015
  }
914
1016
  async query(vector, topK, namespace, filter) {
915
1017
  var _a2;
1018
+ const targetIdx = await this.getActiveIndex(namespace);
916
1019
  const pineconeFilter = this.sanitizeFilter(filter);
917
- const result = await this.index(namespace).query(__spreadValues({
1020
+ const result = await targetIdx.query(__spreadValues({
918
1021
  vector,
919
1022
  topK,
920
1023
  includeMetadata: true
@@ -930,13 +1033,17 @@ var init_PineconeProvider = __esm({
930
1033
  });
931
1034
  }
932
1035
  async delete(id, namespace) {
933
- await this.index(namespace).deleteOne({ id: String(id) });
1036
+ const targetIdx = await this.getActiveIndex(namespace);
1037
+ await targetIdx.deleteOne({ id: String(id) });
934
1038
  }
935
1039
  async deleteNamespace(namespace) {
936
- await this.client.index(this.indexName).namespace(namespace).deleteAll();
1040
+ const targetIdx = await this.getActiveIndex(namespace);
1041
+ await targetIdx.deleteAll();
937
1042
  }
938
1043
  async ping() {
939
1044
  try {
1045
+ if (!this.client) await this.initialize();
1046
+ if (!this.client) return false;
940
1047
  await this.client.listIndexes();
941
1048
  return true;
942
1049
  } catch (e) {
@@ -3229,7 +3336,7 @@ function getEnvConfig(env = process.env, base) {
3229
3336
  return true;
3230
3337
  }
3231
3338
  })();
3232
- const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://llm.retrivora.com/api/v1";
3339
+ const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://retrivora.com/api/v1";
3233
3340
  const defaultLlmProvider = isFreeTier ? "universal_rest" : "universal_rest";
3234
3341
  const llmProvider = (_sa = (_ra = readEnum(env, "LLM_PROVIDER", defaultLlmProvider, LLM_PROVIDERS)) != null ? _ra : (_qa = base == null ? void 0 : base.llm) == null ? void 0 : _qa.provider) != null ? _sa : defaultLlmProvider;
3235
3342
  const llmBaseUrl = (_wa = (_va = (_ta = readString(env, "LITELLM_BASE_URL")) != null ? _ta : readString(env, "LLM_BASE_URL")) != null ? _va : (_ua = base == null ? void 0 : base.llm) == null ? void 0 : _ua.baseUrl) != null ? _wa : defaultGatewayUrl;
package/dist/server.mjs CHANGED
@@ -778,6 +778,84 @@ var init_BaseVectorProvider = __esm({
778
778
  }
779
779
  });
780
780
 
781
+ // src/core/ConfigFetcher.ts
782
+ var ConfigFetcher;
783
+ var init_ConfigFetcher = __esm({
784
+ "src/core/ConfigFetcher.ts"() {
785
+ "use strict";
786
+ ConfigFetcher = class {
787
+ // 5-minute in-memory session cache
788
+ /**
789
+ * Fetch full project configuration (vectorDb + embedding + llm) from Retrivora Control Plane.
790
+ */
791
+ static async fetchRemoteConfig(projectId, licenseKey) {
792
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
793
+ const cacheKey = `${projectId}:${licenseKey || ""}`;
794
+ const now = Date.now();
795
+ const cached = this.cache.get(cacheKey);
796
+ if (cached && now - cached.cachedAt < this.TTL_MS) {
797
+ return cached.config;
798
+ }
799
+ const controlPlaneUrls = [
800
+ process.env.RETRIVORA_CONTROL_PLANE_URL,
801
+ process.env.NEXT_PUBLIC_RETRIVORA_CONTROL_PLANE_URL,
802
+ "https://retrivora.com",
803
+ "http://localhost:3000"
804
+ ].filter(Boolean);
805
+ for (const baseUrl of controlPlaneUrls) {
806
+ try {
807
+ const url = `${baseUrl.replace(/\/$/, "")}/api/v1/config?projectId=${encodeURIComponent(projectId)}${licenseKey ? `&licenseKey=${encodeURIComponent(licenseKey)}` : ""}`;
808
+ const res = await fetch(url, {
809
+ method: "GET",
810
+ headers: __spreadValues({
811
+ "Content-Type": "application/json"
812
+ }, licenseKey ? { "x-license-key": licenseKey } : {})
813
+ });
814
+ if (res.ok) {
815
+ const data = await res.json();
816
+ if ((data == null ? void 0 : data.success) && ((_a2 = data == null ? void 0 : data.vectorDb) == null ? void 0 : _a2.apiKey)) {
817
+ const config = {
818
+ vectorDb: {
819
+ apiKey: data.vectorDb.apiKey,
820
+ indexName: data.vectorDb.indexName || "retrivora-free",
821
+ provider: data.vectorDb.provider || "pinecone"
822
+ },
823
+ embedding: {
824
+ provider: ((_b = data.embedding) == null ? void 0 : _b.provider) || "universal_rest",
825
+ model: ((_c = data.embedding) == null ? void 0 : _c.model) || "text-embedding-004",
826
+ baseUrl: ((_d = data.embedding) == null ? void 0 : _d.baseUrl) || "https://llm.retrivora.com/api/v1",
827
+ apiKey: ((_e = data.embedding) == null ? void 0 : _e.apiKey) || licenseKey || "",
828
+ profile: ((_f = data.embedding) == null ? void 0 : _f.profile) || "litellm"
829
+ },
830
+ llm: {
831
+ provider: ((_g2 = data.llm) == null ? void 0 : _g2.provider) || "universal_rest",
832
+ model: ((_h = data.llm) == null ? void 0 : _h.model) || "llama-3.1-8b-instant",
833
+ baseUrl: ((_i = data.llm) == null ? void 0 : _i.baseUrl) || "https://llm.retrivora.com/api/v1",
834
+ apiKey: ((_j = data.llm) == null ? void 0 : _j.apiKey) || licenseKey || "",
835
+ profile: ((_k = data.llm) == null ? void 0 : _k.profile) || "litellm"
836
+ }
837
+ };
838
+ this.cache.set(cacheKey, { config, cachedAt: now });
839
+ return config;
840
+ }
841
+ }
842
+ } catch (e) {
843
+ }
844
+ }
845
+ return null;
846
+ }
847
+ /** Convenience: fetch only vector DB config (backwards compat). */
848
+ static async fetchRemoteVectorConfig(projectId, licenseKey) {
849
+ var _a2;
850
+ const config = await this.fetchRemoteConfig(projectId, licenseKey);
851
+ return (_a2 = config == null ? void 0 : config.vectorDb) != null ? _a2 : null;
852
+ }
853
+ };
854
+ ConfigFetcher.cache = /* @__PURE__ */ new Map();
855
+ ConfigFetcher.TTL_MS = 5 * 60 * 1e3;
856
+ }
857
+ });
858
+
781
859
  // src/providers/vectordb/PineconeProvider.ts
782
860
  var PineconeProvider_exports = {};
783
861
  __export(PineconeProvider_exports, {
@@ -789,6 +867,7 @@ var init_PineconeProvider = __esm({
789
867
  "src/providers/vectordb/PineconeProvider.ts"() {
790
868
  "use strict";
791
869
  init_BaseVectorProvider();
870
+ init_ConfigFetcher();
792
871
  PineconeProvider = class extends BaseVectorProvider {
793
872
  constructor(config) {
794
873
  super(config);
@@ -854,27 +933,49 @@ var init_PineconeProvider = __esm({
854
933
  }
855
934
  async initialize() {
856
935
  var _a2, _b;
857
- const key = this.apiKey || process.env.PINECONE_API_KEY || "";
936
+ if (this.client) return;
937
+ let key = this.apiKey || process.env.PINECONE_API_KEY || "";
938
+ if (!key) {
939
+ const projectId = process.env.RAG_PROJECT_ID || process.env.NEXT_PUBLIC_RAG_PROJECT_ID || "my-rag-app";
940
+ const licenseKey = process.env.RETRIVORA_LICENSE_KEY || process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY;
941
+ const remoteConfig = await ConfigFetcher.fetchRemoteVectorConfig(projectId, licenseKey);
942
+ if (remoteConfig == null ? void 0 : remoteConfig.apiKey) {
943
+ key = remoteConfig.apiKey;
944
+ this.apiKey = key;
945
+ if (remoteConfig.indexName) {
946
+ this.indexName = remoteConfig.indexName;
947
+ }
948
+ }
949
+ }
858
950
  if (!key) {
859
- console.log("[PineconeProvider] Keyless Mode active \u2014 Vector operations managed via Retrivora Cloud Gateway.");
951
+ console.warn("[PineconeProvider] Warning: No Pinecone API key available locally or remotely.");
860
952
  return;
861
953
  }
862
954
  this.client = new Pinecone({ apiKey: key });
863
- const indexes = await this.client.listIndexes();
864
- const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
865
- if (!names.includes(this.indexName)) {
866
- throw new Error(
867
- `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
868
- );
955
+ try {
956
+ const indexes = await this.client.listIndexes();
957
+ const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
958
+ if (!names.includes(this.indexName)) {
959
+ console.warn(`[PineconeProvider] Target index "${this.indexName}" not listed. Proceeding with configured index name.`);
960
+ }
961
+ } catch (err) {
962
+ console.warn("[PineconeProvider] List index verification warning:", err instanceof Error ? err.message : String(err));
869
963
  }
870
964
  }
871
- index(namespace) {
965
+ async getActiveIndex(namespace) {
966
+ if (!this.client) {
967
+ await this.initialize();
968
+ }
969
+ if (!this.client) {
970
+ throw new Error("[PineconeProvider] Cannot execute vector operation: Pinecone client failed to initialize.");
971
+ }
872
972
  const idx = this.client.index(this.indexName);
873
973
  return namespace ? idx.namespace(namespace) : idx.namespace("");
874
974
  }
875
975
  async upsert(doc, namespace) {
876
976
  var _a2;
877
- await this.index(namespace).upsert({
977
+ const targetIdx = await this.getActiveIndex(namespace);
978
+ await targetIdx.upsert({
878
979
  records: [{
879
980
  id: String(doc.id),
880
981
  values: doc.vector,
@@ -883,6 +984,7 @@ var init_PineconeProvider = __esm({
883
984
  });
884
985
  }
885
986
  async batchUpsert(docs, namespace) {
987
+ const targetIdx = await this.getActiveIndex(namespace);
886
988
  const BATCH = 100;
887
989
  for (let i = 0; i < docs.length; i += BATCH) {
888
990
  const records = docs.slice(i, i + BATCH).map((d) => {
@@ -893,13 +995,14 @@ var init_PineconeProvider = __esm({
893
995
  metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
894
996
  };
895
997
  });
896
- await this.index(namespace).upsert({ records });
998
+ await targetIdx.upsert({ records });
897
999
  }
898
1000
  }
899
1001
  async query(vector, topK, namespace, filter) {
900
1002
  var _a2;
1003
+ const targetIdx = await this.getActiveIndex(namespace);
901
1004
  const pineconeFilter = this.sanitizeFilter(filter);
902
- const result = await this.index(namespace).query(__spreadValues({
1005
+ const result = await targetIdx.query(__spreadValues({
903
1006
  vector,
904
1007
  topK,
905
1008
  includeMetadata: true
@@ -915,13 +1018,17 @@ var init_PineconeProvider = __esm({
915
1018
  });
916
1019
  }
917
1020
  async delete(id, namespace) {
918
- await this.index(namespace).deleteOne({ id: String(id) });
1021
+ const targetIdx = await this.getActiveIndex(namespace);
1022
+ await targetIdx.deleteOne({ id: String(id) });
919
1023
  }
920
1024
  async deleteNamespace(namespace) {
921
- await this.client.index(this.indexName).namespace(namespace).deleteAll();
1025
+ const targetIdx = await this.getActiveIndex(namespace);
1026
+ await targetIdx.deleteAll();
922
1027
  }
923
1028
  async ping() {
924
1029
  try {
1030
+ if (!this.client) await this.initialize();
1031
+ if (!this.client) return false;
925
1032
  await this.client.listIndexes();
926
1033
  return true;
927
1034
  } catch (e) {
@@ -3132,7 +3239,7 @@ function getEnvConfig(env = process.env, base) {
3132
3239
  return true;
3133
3240
  }
3134
3241
  })();
3135
- const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://llm.retrivora.com/api/v1";
3242
+ const defaultGatewayUrl = (_pa = (_oa = readString(env, "LITELLM_BASE_URL")) != null ? _oa : readString(env, "LLM_BASE_URL")) != null ? _pa : "https://retrivora.com/api/v1";
3136
3243
  const defaultLlmProvider = isFreeTier ? "universal_rest" : "universal_rest";
3137
3244
  const llmProvider = (_sa = (_ra = readEnum(env, "LLM_PROVIDER", defaultLlmProvider, LLM_PROVIDERS)) != null ? _ra : (_qa = base == null ? void 0 : base.llm) == null ? void 0 : _qa.provider) != null ? _sa : defaultLlmProvider;
3138
3245
  const llmBaseUrl = (_wa = (_va = (_ta = readString(env, "LITELLM_BASE_URL")) != null ? _ta : readString(env, "LLM_BASE_URL")) != null ? _va : (_ua = base == null ? void 0 : base.llm) == null ? void 0 : _ua.baseUrl) != null ? _wa : defaultGatewayUrl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "2.1.9",
3
+ "version": "2.2.0",
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",
@@ -171,7 +171,10 @@ export function getEnvConfig(env: Record<string, string | undefined> = process.e
171
171
  }
172
172
  })();
173
173
 
174
- const defaultGatewayUrl = readString(env, 'LITELLM_BASE_URL') ?? readString(env, 'LLM_BASE_URL') ?? 'https://llm.retrivora.com/api/v1';
174
+ // Default gateway: retrivora.com/api/v1 acts as a secure proxy that validates the license key
175
+ // and forwards to llm.retrivora.com with LITELLM_MASTER_KEY (which end-users never need to know).
176
+ // Developers who self-host can override with LITELLM_BASE_URL.
177
+ const defaultGatewayUrl = readString(env, 'LITELLM_BASE_URL') ?? readString(env, 'LLM_BASE_URL') ?? 'https://retrivora.com/api/v1';
175
178
 
176
179
  const defaultLlmProvider = isFreeTier ? 'universal_rest' : 'universal_rest';
177
180
  const llmProvider = (readEnum(env, 'LLM_PROVIDER', defaultLlmProvider, LLM_PROVIDERS) ?? base?.llm?.provider ?? defaultLlmProvider) as LLMProvider;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * ConfigFetcher.ts — Dynamically fetches project credentials from Retrivora Control Plane
3
+ * without hardcoding plain-text master keys in NPM package binaries.
4
+ */
5
+
6
+ export interface RemoteVectorConfig {
7
+ apiKey: string;
8
+ indexName: string;
9
+ provider: string;
10
+ }
11
+
12
+ export interface RemoteEmbeddingConfig {
13
+ provider: string;
14
+ model: string;
15
+ baseUrl: string;
16
+ apiKey: string;
17
+ profile?: string;
18
+ }
19
+
20
+ export interface RemoteLLMConfig {
21
+ provider: string;
22
+ model: string;
23
+ baseUrl: string;
24
+ apiKey: string;
25
+ profile?: string;
26
+ }
27
+
28
+ export interface RemoteConfig {
29
+ vectorDb: RemoteVectorConfig;
30
+ embedding: RemoteEmbeddingConfig;
31
+ llm: RemoteLLMConfig;
32
+ }
33
+
34
+ // Legacy alias
35
+ export type { RemoteVectorConfig as RemoteConfig_ };
36
+
37
+ export class ConfigFetcher {
38
+ private static cache = new Map<string, { config: RemoteConfig; cachedAt: number }>();
39
+ private static readonly TTL_MS = 5 * 60 * 1000; // 5-minute in-memory session cache
40
+
41
+ /**
42
+ * Fetch full project configuration (vectorDb + embedding + llm) from Retrivora Control Plane.
43
+ */
44
+ static async fetchRemoteConfig(projectId: string, licenseKey?: string): Promise<RemoteConfig | null> {
45
+ const cacheKey = `${projectId}:${licenseKey || ''}`;
46
+ const now = Date.now();
47
+ const cached = this.cache.get(cacheKey);
48
+
49
+ if (cached && now - cached.cachedAt < this.TTL_MS) {
50
+ return cached.config;
51
+ }
52
+
53
+ const controlPlaneUrls = [
54
+ process.env.RETRIVORA_CONTROL_PLANE_URL,
55
+ process.env.NEXT_PUBLIC_RETRIVORA_CONTROL_PLANE_URL,
56
+ 'https://retrivora.com',
57
+ 'http://localhost:3000',
58
+ ].filter(Boolean) as string[];
59
+
60
+ for (const baseUrl of controlPlaneUrls) {
61
+ try {
62
+ const url = `${baseUrl.replace(/\/$/, '')}/api/v1/config?projectId=${encodeURIComponent(projectId)}${licenseKey ? `&licenseKey=${encodeURIComponent(licenseKey)}` : ''}`;
63
+ const res = await fetch(url, {
64
+ method: 'GET',
65
+ headers: {
66
+ 'Content-Type': 'application/json',
67
+ ...(licenseKey ? { 'x-license-key': licenseKey } : {}),
68
+ },
69
+ });
70
+
71
+ if (res.ok) {
72
+ const data = await res.json();
73
+ if (data?.success && data?.vectorDb?.apiKey) {
74
+ const config: RemoteConfig = {
75
+ vectorDb: {
76
+ apiKey: data.vectorDb.apiKey,
77
+ indexName: data.vectorDb.indexName || 'retrivora-free',
78
+ provider: data.vectorDb.provider || 'pinecone',
79
+ },
80
+ embedding: {
81
+ provider: data.embedding?.provider || 'universal_rest',
82
+ model: data.embedding?.model || 'text-embedding-004',
83
+ baseUrl: data.embedding?.baseUrl || 'https://llm.retrivora.com/api/v1',
84
+ apiKey: data.embedding?.apiKey || licenseKey || '',
85
+ profile: data.embedding?.profile || 'litellm',
86
+ },
87
+ llm: {
88
+ provider: data.llm?.provider || 'universal_rest',
89
+ model: data.llm?.model || 'llama-3.1-8b-instant',
90
+ baseUrl: data.llm?.baseUrl || 'https://llm.retrivora.com/api/v1',
91
+ apiKey: data.llm?.apiKey || licenseKey || '',
92
+ profile: data.llm?.profile || 'litellm',
93
+ },
94
+ };
95
+ this.cache.set(cacheKey, { config, cachedAt: now });
96
+ return config;
97
+ }
98
+ }
99
+ } catch {
100
+ /* Try next fallback URL */
101
+ }
102
+ }
103
+
104
+ return null;
105
+ }
106
+
107
+ /** Convenience: fetch only vector DB config (backwards compat). */
108
+ static async fetchRemoteVectorConfig(projectId: string, licenseKey?: string): Promise<RemoteVectorConfig | null> {
109
+ const config = await this.fetchRemoteConfig(projectId, licenseKey);
110
+ return config?.vectorDb ?? null;
111
+ }
112
+ }
@@ -8,7 +8,7 @@ import { IProviderValidator, IProviderHealthChecker } from '../../core/ProviderI
8
8
  */
9
9
  export abstract class BaseVectorProvider {
10
10
  protected readonly config: VectorDBConfig;
11
- protected readonly indexName: string;
11
+ protected indexName: string;
12
12
 
13
13
  constructor(config: VectorDBConfig) {
14
14
  this.config = config;
@@ -4,13 +4,14 @@ import { BaseVectorProvider } from './BaseVectorProvider';
4
4
  import { VectorMatch, UpsertDocument } from '../../types';
5
5
  import { IProviderValidator, IProviderHealthChecker, HealthCheckResult } from '../../core/ProviderInterfaces';
6
6
  import { ValidationError } from '../../core/ConfigValidator';
7
+ import { ConfigFetcher } from '../../core/ConfigFetcher';
7
8
 
8
9
  /**
9
10
  * PineconeProvider — Pinecone vector database implementation.
10
11
  */
11
12
  export class PineconeProvider extends BaseVectorProvider {
12
13
  private client!: Pinecone;
13
- private readonly apiKey: string;
14
+ private apiKey: string;
14
15
 
15
16
  constructor(config: VectorDBConfig) {
16
17
  super(config);
@@ -82,28 +83,55 @@ export class PineconeProvider extends BaseVectorProvider {
82
83
  }
83
84
 
84
85
  async initialize(): Promise<void> {
85
- const key = this.apiKey || process.env.PINECONE_API_KEY || '';
86
+ if (this.client) return;
87
+
88
+ let key = this.apiKey || process.env.PINECONE_API_KEY || '';
89
+
90
+ if (!key) {
91
+ const projectId = process.env.RAG_PROJECT_ID || process.env.NEXT_PUBLIC_RAG_PROJECT_ID || 'my-rag-app';
92
+ const licenseKey = process.env.RETRIVORA_LICENSE_KEY || process.env.NEXT_PUBLIC_RETRIVORA_LICENSE_KEY;
93
+
94
+ const remoteConfig = await ConfigFetcher.fetchRemoteVectorConfig(projectId, licenseKey);
95
+ if (remoteConfig?.apiKey) {
96
+ key = remoteConfig.apiKey;
97
+ this.apiKey = key;
98
+ if (remoteConfig.indexName) {
99
+ this.indexName = remoteConfig.indexName;
100
+ }
101
+ }
102
+ }
103
+
86
104
  if (!key) {
87
- console.log('[PineconeProvider] Keyless Mode active Vector operations managed via Retrivora Cloud Gateway.');
105
+ console.warn('[PineconeProvider] Warning: No Pinecone API key available locally or remotely.');
88
106
  return;
89
107
  }
108
+
90
109
  this.client = new Pinecone({ apiKey: key });
91
- const indexes = await this.client.listIndexes();
92
- const names = indexes.indexes?.map((i) => i.name) ?? [];
93
- if (!names.includes(this.indexName)) {
94
- throw new Error(
95
- `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(', ')}`
96
- );
110
+ try {
111
+ const indexes = await this.client.listIndexes();
112
+ const names = indexes.indexes?.map((i) => i.name) ?? [];
113
+ if (!names.includes(this.indexName)) {
114
+ console.warn(`[PineconeProvider] Target index "${this.indexName}" not listed. Proceeding with configured index name.`);
115
+ }
116
+ } catch (err) {
117
+ console.warn('[PineconeProvider] List index verification warning:', err instanceof Error ? err.message : String(err));
97
118
  }
98
119
  }
99
120
 
100
- private index(namespace?: string) {
121
+ private async getActiveIndex(namespace?: string) {
122
+ if (!this.client) {
123
+ await this.initialize();
124
+ }
125
+ if (!this.client) {
126
+ throw new Error('[PineconeProvider] Cannot execute vector operation: Pinecone client failed to initialize.');
127
+ }
101
128
  const idx = this.client.index(this.indexName);
102
129
  return namespace ? idx.namespace(namespace) : idx.namespace('');
103
130
  }
104
131
 
105
132
  async upsert(doc: UpsertDocument, namespace?: string): Promise<void> {
106
- await this.index(namespace).upsert({
133
+ const targetIdx = await this.getActiveIndex(namespace);
134
+ await targetIdx.upsert({
107
135
  records: [{
108
136
  id: String(doc.id),
109
137
  values: doc.vector,
@@ -113,6 +141,7 @@ export class PineconeProvider extends BaseVectorProvider {
113
141
  }
114
142
 
115
143
  async batchUpsert(docs: UpsertDocument[], namespace?: string): Promise<void> {
144
+ const targetIdx = await this.getActiveIndex(namespace);
116
145
  const BATCH = 100;
117
146
  for (let i = 0; i < docs.length; i += BATCH) {
118
147
  const records = docs.slice(i, i + BATCH).map((d) => ({
@@ -120,7 +149,7 @@ export class PineconeProvider extends BaseVectorProvider {
120
149
  values: d.vector,
121
150
  metadata: { content: d.content, ...(d.metadata ?? {}) } as RecordMetadata,
122
151
  }));
123
- await this.index(namespace).upsert({ records });
152
+ await targetIdx.upsert({ records });
124
153
  }
125
154
  }
126
155
 
@@ -130,8 +159,9 @@ export class PineconeProvider extends BaseVectorProvider {
130
159
  namespace?: string,
131
160
  filter?: Record<string, unknown>
132
161
  ): Promise<VectorMatch[]> {
162
+ const targetIdx = await this.getActiveIndex(namespace);
133
163
  const pineconeFilter = this.sanitizeFilter(filter);
134
- const result = await this.index(namespace).query({
164
+ const result = await targetIdx.query({
135
165
  vector,
136
166
  topK,
137
167
  includeMetadata: true,
@@ -146,15 +176,19 @@ export class PineconeProvider extends BaseVectorProvider {
146
176
  }
147
177
 
148
178
  async delete(id: string | number, namespace?: string): Promise<void> {
149
- await this.index(namespace).deleteOne({ id: String(id) });
179
+ const targetIdx = await this.getActiveIndex(namespace);
180
+ await targetIdx.deleteOne({ id: String(id) });
150
181
  }
151
182
 
152
183
  async deleteNamespace(namespace: string): Promise<void> {
153
- await this.client.index(this.indexName).namespace(namespace).deleteAll();
184
+ const targetIdx = await this.getActiveIndex(namespace);
185
+ await targetIdx.deleteAll();
154
186
  }
155
187
 
156
188
  async ping(): Promise<boolean> {
157
189
  try {
190
+ if (!this.client) await this.initialize();
191
+ if (!this.client) return false;
158
192
  await this.client.listIndexes();
159
193
  return true;
160
194
  } catch {