@coderule/clients 1.1.0 → 1.4.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.
package/dist/index.js CHANGED
@@ -237,18 +237,41 @@ init_esm_shims();
237
237
  var SyncHttpClient = class {
238
238
  /**
239
239
  * Initialize the Sync HTTP client
240
- * @param baseUrl - Base URL of the Sync service (e.g., "http://localhost:8002")
241
- * @param jwtToken - JWT token for authentication
242
- * @param timeout - Request timeout in milliseconds (default: 60000)
240
+ * @param config.baseUrl - URI/URL for connecting to the HTTP server (e.g., "http://localhost:8002")
241
+ * @param config.timeout - Request timeout in milliseconds (default: 60000)
242
+ * @param config.jwtProvider - Provider for obtaining JWT tokens
243
243
  */
244
- constructor(baseUrl, jwtToken, timeout = 6e4) {
245
- this.baseUrl = baseUrl.replace(/\/$/, "");
246
- this.jwtToken = jwtToken;
244
+ constructor({
245
+ baseUrl = "http://localhost:8002",
246
+ timeout = 6e4,
247
+ jwtProvider
248
+ }) {
249
+ if (!jwtProvider) {
250
+ throw new Error("SyncHttpClient requires a JWT provider");
251
+ }
247
252
  this.timeout = timeout;
248
- this.headers = {
249
- Authorization: `Bearer ${jwtToken}`,
250
- "Content-Type": "application/json"
251
- };
253
+ this.jwtProvider = jwtProvider;
254
+ this.configureBase(baseUrl);
255
+ }
256
+ updateBaseUrl(baseUrl) {
257
+ this.configureBase(baseUrl);
258
+ }
259
+ configureBase(uri) {
260
+ let processedUri = uri;
261
+ if (!uri.startsWith("http://") && !uri.startsWith("https://")) {
262
+ processedUri = `http://${uri}`;
263
+ }
264
+ const url = new URL(processedUri);
265
+ if (url.pathname && url.pathname !== "/") {
266
+ this.baseUrl = `${url.protocol}//${url.host}${url.pathname}`;
267
+ } else {
268
+ this.baseUrl = `${url.protocol}//${url.host}`;
269
+ }
270
+ if (this.baseUrl.endsWith("/")) {
271
+ this.apiBase = `${this.baseUrl}sync/v1/`;
272
+ } else {
273
+ this.apiBase = `${this.baseUrl}/sync/v1/`;
274
+ }
252
275
  }
253
276
  /**
254
277
  * Check the status of a snapshot
@@ -257,13 +280,20 @@ var SyncHttpClient = class {
257
280
  * @throws Error on HTTP errors or connection errors
258
281
  */
259
282
  async checkSnapshotStatus(snapshotHash) {
260
- const url = `${this.baseUrl}/sync/v1/snapshots`;
283
+ if (!snapshotHash) {
284
+ throw new Error("Snapshot hash must be provided");
285
+ }
286
+ const jwt = await this.jwtProvider.getJWT();
287
+ const url = `${this.apiBase}snapshots`;
261
288
  try {
262
289
  const controller = new AbortController2();
263
290
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
264
291
  const response = await fetch_wrapper_default(url, {
265
292
  method: "POST",
266
- headers: this.headers,
293
+ headers: {
294
+ Authorization: `Bearer ${jwt}`,
295
+ "Content-Type": "application/json"
296
+ },
267
297
  body: JSON.stringify({ snapshot_hash: snapshotHash }),
268
298
  signal: controller.signal
269
299
  });
@@ -295,13 +325,20 @@ var SyncHttpClient = class {
295
325
  * @throws Error on HTTP errors or connection errors
296
326
  */
297
327
  async createSnapshot(snapshotHash, files) {
298
- const url = `${this.baseUrl}/sync/v1/snapshots`;
328
+ if (!snapshotHash) {
329
+ throw new Error("Snapshot hash must be provided");
330
+ }
331
+ const jwt = await this.jwtProvider.getJWT();
332
+ const url = `${this.apiBase}snapshots`;
299
333
  try {
300
334
  const controller = new AbortController2();
301
335
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
302
336
  const response = await fetch_wrapper_default(url, {
303
337
  method: "POST",
304
- headers: this.headers,
338
+ headers: {
339
+ Authorization: `Bearer ${jwt}`,
340
+ "Content-Type": "application/json"
341
+ },
305
342
  body: JSON.stringify({
306
343
  snapshot_hash: snapshotHash,
307
344
  files
@@ -342,7 +379,8 @@ var SyncHttpClient = class {
342
379
  * @throws Error on HTTP errors or connection errors
343
380
  */
344
381
  async uploadFileContent(filesContent) {
345
- const url = `${this.baseUrl}/sync/v1/files/content`;
382
+ const jwt = await this.jwtProvider.getJWT();
383
+ const url = `${this.apiBase}files/content`;
346
384
  try {
347
385
  const controller = new AbortController2();
348
386
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
@@ -352,8 +390,9 @@ var SyncHttpClient = class {
352
390
  const blob = new Blob([content], { type: "application/octet-stream" });
353
391
  formData.append(fileHash, blob, fileData.path);
354
392
  }
355
- const uploadHeaders = { ...this.headers };
356
- delete uploadHeaders["Content-Type"];
393
+ const uploadHeaders = {
394
+ Authorization: `Bearer ${jwt}`
395
+ };
357
396
  const response = await fetch_wrapper_default(url, {
358
397
  method: "POST",
359
398
  headers: uploadHeaders,
@@ -410,13 +449,13 @@ var SyncHttpClient = class {
410
449
  * @throws Error on HTTP errors or connection errors
411
450
  */
412
451
  async health() {
413
- const url = `${this.baseUrl}/sync/v1/health`;
452
+ const url = `${this.apiBase}health`;
414
453
  try {
415
454
  const controller = new AbortController2();
416
455
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
417
456
  const response = await fetch_wrapper_default(url, {
418
457
  method: "GET",
419
- headers: { Authorization: `Bearer ${this.jwtToken}` },
458
+ // No authentication required for health check
420
459
  signal: controller.signal
421
460
  });
422
461
  clearTimeout(timeoutId);
@@ -448,10 +487,28 @@ init_esm_shims();
448
487
  var RetrievalHttpClient = class {
449
488
  /**
450
489
  * Initialize the Retrieval HTTP client
451
- * @param uri - URI/URL for connecting to the HTTP server (e.g., "http://localhost:8004")
452
- * @param timeout - Request timeout in milliseconds (default: 60000)
490
+ * @param config.baseUrl - URI/URL for connecting to the HTTP server (e.g., "http://localhost:8004")
491
+ * @param config.timeout - Request timeout in milliseconds (default: 60000)
492
+ * @param config.jwtProvider - Provider for obtaining JWT tokens
453
493
  */
454
- constructor(uri = "http://localhost:8004", timeout = 6e4) {
494
+ constructor({
495
+ baseUrl = "http://localhost:8004",
496
+ timeout = 6e4,
497
+ jwtProvider
498
+ }) {
499
+ if (!jwtProvider) {
500
+ throw new Error("RetrievalHttpClient requires a JWT provider");
501
+ }
502
+ this.timeout = timeout;
503
+ this.jwtProvider = jwtProvider;
504
+ this.configureBase(baseUrl);
505
+ console.debug(`Initialized HTTP client for ${this.baseUrl}`);
506
+ console.debug(`API base: ${this.apiBase}`);
507
+ }
508
+ updateBaseUrl(baseUrl) {
509
+ this.configureBase(baseUrl);
510
+ }
511
+ configureBase(uri) {
455
512
  let processedUri = uri;
456
513
  if (!uri.startsWith("http://") && !uri.startsWith("https://")) {
457
514
  processedUri = `http://${uri}`;
@@ -462,14 +519,11 @@ var RetrievalHttpClient = class {
462
519
  } else {
463
520
  this.baseUrl = `${url.protocol}//${url.host}`;
464
521
  }
465
- this.timeout = timeout;
466
522
  if (this.baseUrl.endsWith("/")) {
467
523
  this.apiBase = `${this.baseUrl}api/retrieval/`;
468
524
  } else {
469
525
  this.apiBase = `${this.baseUrl}/api/retrieval/`;
470
526
  }
471
- console.debug(`Initialized HTTP client for ${this.baseUrl}`);
472
- console.debug(`API base: ${this.apiBase}`);
473
527
  }
474
528
  /**
475
529
  * Check the health status of the Retrieval service
@@ -518,25 +572,22 @@ var RetrievalHttpClient = class {
518
572
  * @param snapshotHash - SHA256 hash of the codebase snapshot
519
573
  * @param queryText - Natural language query for retrieval
520
574
  * @param budgetTokens - Maximum token budget for results (default: 3000)
521
- * @param jwt - JWT token for authorization (required)
522
575
  * @param options - Optional retrieval parameters
523
576
  * @returns Retrieval results with formatted output
524
577
  * @throws Error on query failures
525
578
  */
526
- async query(snapshotHash, queryText, budgetTokens = 3e3, jwt, options) {
579
+ async query(snapshotHash, queryText, budgetTokens = 3e3, options) {
527
580
  if (!snapshotHash) {
528
581
  throw new Error("Snapshot hash must be provided");
529
582
  }
530
583
  if (!queryText) {
531
584
  throw new Error("Query text must be provided");
532
585
  }
533
- if (!jwt) {
534
- throw new Error("JWT must be provided");
535
- }
536
586
  if (budgetTokens < 100) {
537
587
  throw new Error("Budget tokens must be at least 100");
538
588
  }
539
589
  const startTime = Date.now();
590
+ const jwt = await this.jwtProvider.getJWT();
540
591
  const queryEndpoint = `${this.apiBase}query`;
541
592
  try {
542
593
  const controller = new AbortController2();
@@ -593,13 +644,11 @@ var RetrievalHttpClient = class {
593
644
  * @returns Snapshot status information
594
645
  * @throws Error on status check failures
595
646
  */
596
- async checkSnapshotStatus(snapshotHash, jwt) {
647
+ async checkSnapshotStatus(snapshotHash) {
597
648
  if (!snapshotHash) {
598
649
  throw new Error("Snapshot hash must be provided");
599
650
  }
600
- if (!jwt) {
601
- throw new Error("JWT must be provided");
602
- }
651
+ const jwt = await this.jwtProvider.getJWT();
603
652
  const statusEndpoint = `${this.apiBase}snapshots/${snapshotHash}/status`;
604
653
  try {
605
654
  const controller = new AbortController2();
@@ -644,10 +693,8 @@ var RetrievalHttpClient = class {
644
693
  * @returns true if cache cleared successfully
645
694
  * @throws Error on cache clear failures
646
695
  */
647
- async clearCache(jwt) {
648
- if (!jwt) {
649
- throw new Error("JWT must be provided");
650
- }
696
+ async clearCache() {
697
+ const jwt = await this.jwtProvider.getJWT();
651
698
  const cacheEndpoint = `${this.apiBase}cache`;
652
699
  try {
653
700
  const controller = new AbortController2();
@@ -682,10 +729,8 @@ var RetrievalHttpClient = class {
682
729
  * @returns Cache statistics
683
730
  * @throws Error on stats retrieval failures
684
731
  */
685
- async getCacheStats(jwt) {
686
- if (!jwt) {
687
- throw new Error("JWT must be provided");
688
- }
732
+ async getCacheStats() {
733
+ const jwt = await this.jwtProvider.getJWT();
689
734
  const statsEndpoint = `${this.apiBase}cache/stats`;
690
735
  try {
691
736
  const controller = new AbortController2();
@@ -731,7 +776,7 @@ var RetrievalHttpClient = class {
731
776
  * @param formatter - Output format "standard" or "compact"
732
777
  * @returns Retrieval results
733
778
  */
734
- async queryWithOptions(snapshotHash, queryText, jwt, budgetTokens = 3e3, flowStrength = 1.5, blendAlpha = 0.8, hopDepth = 2, maxIterations = 12, split = 0.8, formatter = "standard") {
779
+ async queryWithOptions(snapshotHash, queryText, budgetTokens = 3e3, flowStrength = 1.5, blendAlpha = 0.8, hopDepth = 2, maxIterations = 12, split = 0.8, formatter = "standard") {
735
780
  const options = {
736
781
  flow_strength: flowStrength,
737
782
  blend_alpha: blendAlpha,
@@ -740,7 +785,164 @@ var RetrievalHttpClient = class {
740
785
  split,
741
786
  formatter
742
787
  };
743
- return this.query(snapshotHash, queryText, budgetTokens, jwt, options);
788
+ return this.query(snapshotHash, queryText, budgetTokens, options);
789
+ }
790
+ /**
791
+ * Close the HTTP client connection (no-op for fetch)
792
+ */
793
+ close() {
794
+ }
795
+ };
796
+
797
+ // src/clients/ast-client.ts
798
+ init_esm_shims();
799
+ var ASTHttpClient = class {
800
+ /**
801
+ * Initialize the AST HTTP client
802
+ * @param config.baseUrl - URI/URL for connecting to the HTTP server (e.g., "http://localhost:8003")
803
+ * @param config.timeout - Request timeout in milliseconds (default: 60000)
804
+ * @param config.jwtProvider - Provider for obtaining JWT tokens
805
+ */
806
+ constructor({
807
+ baseUrl = "http://localhost:8003",
808
+ timeout = 6e4,
809
+ jwtProvider
810
+ }) {
811
+ if (!jwtProvider) {
812
+ throw new Error("ASTHttpClient requires a JWT provider");
813
+ }
814
+ this.timeout = timeout;
815
+ this.jwtProvider = jwtProvider;
816
+ this.configureBase(baseUrl);
817
+ }
818
+ updateBaseUrl(baseUrl) {
819
+ this.configureBase(baseUrl);
820
+ }
821
+ configureBase(uri) {
822
+ let processedUri = uri;
823
+ if (!uri.startsWith("http://") && !uri.startsWith("https://")) {
824
+ processedUri = `http://${uri}`;
825
+ }
826
+ const url = new URL(processedUri);
827
+ if (url.pathname && url.pathname !== "/") {
828
+ this.baseUrl = `${url.protocol}//${url.host}${url.pathname}`;
829
+ } else {
830
+ this.baseUrl = `${url.protocol}//${url.host}`;
831
+ }
832
+ if (this.baseUrl.endsWith("/")) {
833
+ this.apiBase = `${this.baseUrl}api/ast/`;
834
+ } else {
835
+ this.apiBase = `${this.baseUrl}/api/ast/`;
836
+ }
837
+ }
838
+ /**
839
+ * Get file visitor rules in v2 format optimized for Chokidar v4
840
+ * @returns Visitor rules with format, include_extensions, include_filenames, exclude_dirnames
841
+ * @throws Error on HTTP errors or connection errors
842
+ */
843
+ async getVisitorRulesV2() {
844
+ const jwt = await this.jwtProvider.getJWT();
845
+ const url = `${this.apiBase}visitor-rules`;
846
+ try {
847
+ const controller = new AbortController2();
848
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
849
+ const response = await fetch_wrapper_default(url, {
850
+ method: "GET",
851
+ headers: {
852
+ Authorization: `Bearer ${jwt}`
853
+ },
854
+ signal: controller.signal
855
+ });
856
+ clearTimeout(timeoutId);
857
+ if (!response.ok) {
858
+ const errorText = await response.text();
859
+ throw new Error(
860
+ `Failed to get visitor rules v2 with status ${response.status}: ${errorText}`
861
+ );
862
+ }
863
+ const data = await response.json();
864
+ if (data.format !== "segments+exts@v2") {
865
+ throw new Error(`Unexpected visitor rules format: ${data.format}`);
866
+ }
867
+ return data;
868
+ } catch (error) {
869
+ if (error.name === "AbortError") {
870
+ throw new Error(`Request timeout after ${this.timeout}ms`);
871
+ }
872
+ console.error(`Failed to get visitor rules v2: ${error.message}`);
873
+ throw error;
874
+ }
875
+ }
876
+ /**
877
+ * Check the health status of the AST service
878
+ * @returns Health status information
879
+ * @throws Error on HTTP errors or connection errors
880
+ */
881
+ async health() {
882
+ const url = `${this.apiBase}health`;
883
+ try {
884
+ const controller = new AbortController2();
885
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
886
+ const response = await fetch_wrapper_default(url, {
887
+ method: "GET",
888
+ // No authentication required for health check
889
+ signal: controller.signal
890
+ });
891
+ clearTimeout(timeoutId);
892
+ if (!response.ok) {
893
+ const errorText = await response.text();
894
+ throw new Error(
895
+ `Health check failed with status ${response.status}: ${errorText}`
896
+ );
897
+ }
898
+ const data = await response.json();
899
+ return data;
900
+ } catch (error) {
901
+ if (error.name === "AbortError") {
902
+ throw new Error(`Request timeout after ${this.timeout}ms`);
903
+ }
904
+ console.error(`Health check failed: ${error.message}`);
905
+ throw error;
906
+ }
907
+ }
908
+ /**
909
+ * Compile visitor rules v2 for use with Chokidar v4
910
+ * This is a helper method that compiles the rules into a format
911
+ * that can be directly used with Chokidar's ignored option
912
+ * @param rules - The visitor rules v2 from the server
913
+ * @returns Compiled rules with Sets and RegExp for efficient matching
914
+ */
915
+ static compileRulesV2(rules) {
916
+ if (rules.format !== "segments+exts@v2") {
917
+ throw new Error(`Unsupported rules format: ${rules.format}`);
918
+ }
919
+ const exts = new Set(rules.include_extensions.map((e) => e.toLowerCase()));
920
+ const names = new Set(rules.include_filenames.map((n) => n.toLowerCase()));
921
+ const dirs = new Set(rules.exclude_dirnames.map((n) => n.toLowerCase()));
922
+ const escapeRe = (s) => s.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
923
+ const dirRe = new RegExp(
924
+ `(?:^|[\\/])(?:${[...dirs].map(escapeRe).join("|")})(?:[\\/]|$)`,
925
+ "i"
926
+ );
927
+ return { exts, names, dirRe };
928
+ }
929
+ /**
930
+ * Build Chokidar v4 `ignored` predicate from compiled rules
931
+ * @param compiled - Compiled rules from compileRulesV2
932
+ * @returns Predicate function that returns true to ignore, false to watch
933
+ */
934
+ static buildIgnoredPredicate(compiled) {
935
+ return (p, stats) => {
936
+ const posix = p.replace(/\\/g, "/");
937
+ if (compiled.dirRe.test(posix)) return true;
938
+ if (stats?.isDirectory?.()) return false;
939
+ const base = posix.split("/").pop()?.toLowerCase() || "";
940
+ if (compiled.names.has(base)) return false;
941
+ const extIndex = base.lastIndexOf(".");
942
+ const ext = extIndex > -1 ? base.slice(extIndex).toLowerCase() : "";
943
+ if (!compiled.exts.has(ext)) return true;
944
+ return false;
945
+ };
744
946
  }
745
947
  /**
746
948
  * Close the HTTP client connection (no-op for fetch)
@@ -749,6 +951,242 @@ var RetrievalHttpClient = class {
749
951
  }
750
952
  };
751
953
 
752
- export { AuthHttpClient, RetrievalHttpClient, SyncHttpClient, decodeJWT, fetch_wrapper_default as fetch };
954
+ // src/utils/jwt-factory.ts
955
+ init_esm_shims();
956
+ var DEFAULT_MIN_TTL_MS = 5e3;
957
+ var JWTFactory = class {
958
+ constructor(authClient, sourceToken, options = {}) {
959
+ this.authClient = authClient;
960
+ this.sourceToken = sourceToken;
961
+ if (!sourceToken) {
962
+ throw new Error("JWTFactory requires a non-empty source token");
963
+ }
964
+ this.minTtlMs = options.minTtlMs ?? DEFAULT_MIN_TTL_MS;
965
+ this.onTokenRefreshed = options.onTokenRefreshed;
966
+ }
967
+ setSourceToken(token) {
968
+ if (!token) {
969
+ throw new Error("JWTFactory requires a non-empty source token");
970
+ }
971
+ if (token !== this.sourceToken) {
972
+ this.sourceToken = token;
973
+ this.cache = void 0;
974
+ this.currentServerUrl = void 0;
975
+ }
976
+ }
977
+ invalidate() {
978
+ this.cache = void 0;
979
+ this.currentServerUrl = void 0;
980
+ }
981
+ async getJWT(forceRefresh = false) {
982
+ const now = Date.now();
983
+ if (!forceRefresh && this.cache) {
984
+ if (now < this.cache.expiresAt) {
985
+ if (now < this.cache.refreshAt) {
986
+ return this.cache.token;
987
+ }
988
+ } else {
989
+ this.cache = void 0;
990
+ }
991
+ }
992
+ return this.refresh(now, forceRefresh);
993
+ }
994
+ async refresh(now, forceRefresh) {
995
+ if (!this.refreshPromise) {
996
+ this.refreshPromise = this.fetchNewToken().finally(() => {
997
+ this.refreshPromise = void 0;
998
+ });
999
+ }
1000
+ try {
1001
+ return await this.refreshPromise;
1002
+ } catch (error) {
1003
+ if (!forceRefresh && this.cache && now < this.cache.expiresAt) {
1004
+ console.warn(
1005
+ "Failed to refresh JWT, using cached token until expiry. Reason:",
1006
+ error
1007
+ );
1008
+ return this.cache.token;
1009
+ }
1010
+ throw error;
1011
+ }
1012
+ }
1013
+ async fetchNewToken() {
1014
+ const response = await this.authClient.authenticate(this.sourceToken);
1015
+ const fetchedAt = Date.now();
1016
+ const expiresAt = this.resolveExpiryMs(
1017
+ response.jwt,
1018
+ response.expires_at,
1019
+ fetchedAt
1020
+ );
1021
+ const payload = decodeJWT(response.jwt);
1022
+ const serverUrl = this.extractServerUrl(payload);
1023
+ const halfLife = Math.max((expiresAt - fetchedAt) / 2, this.minTtlMs);
1024
+ const refreshAt = fetchedAt + halfLife;
1025
+ this.cache = {
1026
+ token: response.jwt,
1027
+ expiresAt,
1028
+ refreshAt,
1029
+ fetchedAt,
1030
+ serverUrl
1031
+ };
1032
+ this.currentServerUrl = serverUrl;
1033
+ this.emitTokenRefreshed({
1034
+ token: response.jwt,
1035
+ expiresAt,
1036
+ serverUrl
1037
+ });
1038
+ return response.jwt;
1039
+ }
1040
+ resolveExpiryMs(jwt, expiresAt, referenceTime) {
1041
+ if (expiresAt) {
1042
+ const parsed = Date.parse(expiresAt);
1043
+ if (!Number.isNaN(parsed) && parsed > referenceTime + this.minTtlMs) {
1044
+ return parsed;
1045
+ }
1046
+ }
1047
+ const decoded = decodeJWT(jwt);
1048
+ if (decoded?.exp) {
1049
+ const expMs = decoded.exp * 1e3;
1050
+ if (expMs > referenceTime + this.minTtlMs) {
1051
+ return expMs;
1052
+ }
1053
+ }
1054
+ return referenceTime + Math.max(this.minTtlMs, 6e4);
1055
+ }
1056
+ extractServerUrl(payload) {
1057
+ const possibleUrl = payload?.server_url;
1058
+ if (typeof possibleUrl === "string" && possibleUrl.trim()) {
1059
+ return possibleUrl.trim();
1060
+ }
1061
+ return void 0;
1062
+ }
1063
+ emitTokenRefreshed(info) {
1064
+ if (this.onTokenRefreshed) {
1065
+ try {
1066
+ this.onTokenRefreshed(info);
1067
+ } catch (error) {
1068
+ console.warn("JWTFactory onTokenRefreshed callback failed:", error);
1069
+ }
1070
+ }
1071
+ }
1072
+ getServerUrl() {
1073
+ return this.currentServerUrl ?? this.cache?.serverUrl;
1074
+ }
1075
+ };
1076
+
1077
+ // src/coderule-clients.ts
1078
+ init_esm_shims();
1079
+ var DEFAULT_AUTH_BASE_URL = "https://r.coderule.ai:16803";
1080
+ var DEFAULT_SERVICE_BASE_URL = "https://s1.coderule.ai:16803";
1081
+ var DEFAULT_TIMEOUTS = {
1082
+ auth: 3e4,
1083
+ ast: 6e4,
1084
+ retrieval: 6e4,
1085
+ sync: 6e4
1086
+ };
1087
+ function resolveOverrides(options) {
1088
+ return {
1089
+ auth: options.auth,
1090
+ ast: options.ast,
1091
+ retrieval: options.retrieval,
1092
+ sync: options.sync
1093
+ };
1094
+ }
1095
+ function resolveTimeout(service, overrides) {
1096
+ return overrides[service]?.timeout ?? DEFAULT_TIMEOUTS[service];
1097
+ }
1098
+ var CoderuleClients = class {
1099
+ constructor(options) {
1100
+ if (!options?.token) {
1101
+ throw new Error("CoderuleClients requires a non-empty token");
1102
+ }
1103
+ const overrides = resolveOverrides(options);
1104
+ const baseUrl = options.baseUrl;
1105
+ const authBase = overrides.auth?.baseUrl ?? baseUrl ?? DEFAULT_AUTH_BASE_URL;
1106
+ const authTimeout = resolveTimeout("auth", overrides);
1107
+ this.auth = new AuthHttpClient(authBase, authTimeout);
1108
+ const userTokenCallback = options.jwtFactory?.onTokenRefreshed;
1109
+ const jwtOptions = {
1110
+ ...options.jwtFactory,
1111
+ onTokenRefreshed: (info) => {
1112
+ userTokenCallback?.(info);
1113
+ if (info.serverUrl) {
1114
+ this.applyServerUrl(info.serverUrl);
1115
+ }
1116
+ }
1117
+ };
1118
+ this.jwtFactory = new JWTFactory(this.auth, options.token, jwtOptions);
1119
+ this.serviceBaseLocked = {
1120
+ ast: Boolean(overrides.ast?.baseUrl),
1121
+ retrieval: Boolean(overrides.retrieval?.baseUrl),
1122
+ sync: Boolean(overrides.sync?.baseUrl)
1123
+ };
1124
+ const defaultServiceBase = baseUrl ?? DEFAULT_SERVICE_BASE_URL;
1125
+ this.ast = new ASTHttpClient({
1126
+ baseUrl: overrides.ast?.baseUrl ?? defaultServiceBase,
1127
+ timeout: resolveTimeout("ast", overrides),
1128
+ jwtProvider: this.jwtFactory
1129
+ });
1130
+ this.retrieval = new RetrievalHttpClient({
1131
+ baseUrl: overrides.retrieval?.baseUrl ?? defaultServiceBase,
1132
+ timeout: resolveTimeout("retrieval", overrides),
1133
+ jwtProvider: this.jwtFactory
1134
+ });
1135
+ this.sync = new SyncHttpClient({
1136
+ baseUrl: overrides.sync?.baseUrl ?? defaultServiceBase,
1137
+ timeout: resolveTimeout("sync", overrides),
1138
+ jwtProvider: this.jwtFactory
1139
+ });
1140
+ const initialServerUrl = this.jwtFactory.getServerUrl();
1141
+ if (initialServerUrl) {
1142
+ this.applyServerUrl(initialServerUrl);
1143
+ }
1144
+ }
1145
+ get jwt() {
1146
+ return this.jwtFactory;
1147
+ }
1148
+ async getJWT(forceRefresh = false) {
1149
+ return this.jwtFactory.getJWT(forceRefresh);
1150
+ }
1151
+ setToken(token) {
1152
+ this.jwtFactory.setSourceToken(token);
1153
+ }
1154
+ close() {
1155
+ this.ast.close();
1156
+ this.retrieval.close();
1157
+ this.sync.close();
1158
+ this.auth.close();
1159
+ }
1160
+ applyServerUrl(serverUrl) {
1161
+ const trimmed = serverUrl.trim();
1162
+ if (!trimmed || this.lastServerUrl === trimmed) {
1163
+ return;
1164
+ }
1165
+ this.lastServerUrl = trimmed;
1166
+ try {
1167
+ if (!this.serviceBaseLocked.ast) {
1168
+ this.ast.updateBaseUrl(trimmed);
1169
+ }
1170
+ } catch (error) {
1171
+ console.warn("Failed to update AST client base URL:", error);
1172
+ }
1173
+ try {
1174
+ if (!this.serviceBaseLocked.retrieval) {
1175
+ this.retrieval.updateBaseUrl(trimmed);
1176
+ }
1177
+ } catch (error) {
1178
+ console.warn("Failed to update Retrieval client base URL:", error);
1179
+ }
1180
+ try {
1181
+ if (!this.serviceBaseLocked.sync) {
1182
+ this.sync.updateBaseUrl(trimmed);
1183
+ }
1184
+ } catch (error) {
1185
+ console.warn("Failed to update Sync client base URL:", error);
1186
+ }
1187
+ }
1188
+ };
1189
+
1190
+ export { ASTHttpClient, AuthHttpClient, CoderuleClients, JWTFactory, RetrievalHttpClient, SyncHttpClient, decodeJWT, fetch_wrapper_default as fetch };
753
1191
  //# sourceMappingURL=index.js.map
754
1192
  //# sourceMappingURL=index.js.map