@heripo/pdf-parser 0.1.23 → 0.1.25

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.cjs CHANGED
@@ -736,6 +736,32 @@ function validatePythonVersion(version, context = "system") {
736
736
  }
737
737
 
738
738
  // src/environment/python-environment.ts
739
+ var DOCLING_SERVE_PACKAGE = "docling-serve==1.16.1";
740
+ var DOCLING_RUNTIME_PACKAGES = [
741
+ "docling-jobkit==1.16.0",
742
+ "docling==2.88.0",
743
+ "docling-core==2.73.0",
744
+ "docling-ibm-models==3.13.0",
745
+ "docling-parse==5.9.0"
746
+ ];
747
+ var DOCLING_SERVE_RUNTIME_PACKAGES = [
748
+ "fastapi[standard]<0.130.0",
749
+ "httpx~=0.28",
750
+ "pydantic~=2.10",
751
+ "pydantic-settings~=2.4",
752
+ "python-multipart<0.1.0,>=0.0.14",
753
+ "typer~=0.12",
754
+ "uvicorn[standard]<1.0.0,>=0.29.0",
755
+ "websockets<17.0,>=14.0",
756
+ "scalar-fastapi>=1.0.3",
757
+ "docling-mcp>=1.0.0",
758
+ "opentelemetry-api==1.36.0",
759
+ "opentelemetry-sdk==1.36.0",
760
+ "opentelemetry-exporter-otlp==1.36.0",
761
+ "opentelemetry-instrumentation-fastapi==0.57b0",
762
+ "opentelemetry-exporter-prometheus==0.57b0",
763
+ "prometheus-client>=0.21.0"
764
+ ];
739
765
  var PythonEnvironment = class {
740
766
  constructor(logger, venvPath) {
741
767
  this.logger = logger;
@@ -747,6 +773,8 @@ var PythonEnvironment = class {
747
773
  await this.upgradePip();
748
774
  await this.installSetuptools();
749
775
  await this.installPyArrow();
776
+ await this.installDoclingRuntimePackages();
777
+ await this.installDoclingServeRuntimePackages();
750
778
  await this.installDoclingServe();
751
779
  }
752
780
  async checkPythonVersion() {
@@ -840,12 +868,30 @@ var PythonEnvironment = class {
840
868
  throw new Error(`Failed to install pyarrow. Exit code: ${result.code}`);
841
869
  }
842
870
  }
871
+ async installDoclingRuntimePackages() {
872
+ const pipPath = (0, import_node_path2.join)(this.venvPath, "bin", "pip");
873
+ const result = await spawnAsync(pipPath, [
874
+ "install",
875
+ "--upgrade",
876
+ ...DOCLING_RUNTIME_PACKAGES
877
+ ]);
878
+ if (result.code !== 0) {
879
+ this.logger.error(
880
+ "[DoclingEnvironment] Failed to install docling runtime packages:",
881
+ result.stderr
882
+ );
883
+ throw new Error(
884
+ `Failed to install docling runtime packages. Exit code: ${result.code}`
885
+ );
886
+ }
887
+ }
843
888
  async installDoclingServe() {
844
889
  const pipPath = (0, import_node_path2.join)(this.venvPath, "bin", "pip");
845
890
  const result = await spawnAsync(pipPath, [
846
891
  "install",
847
892
  "--upgrade",
848
- "docling-serve"
893
+ "--no-deps",
894
+ DOCLING_SERVE_PACKAGE
849
895
  ]);
850
896
  if (result.code !== 0) {
851
897
  this.logger.error(
@@ -857,6 +903,23 @@ var PythonEnvironment = class {
857
903
  );
858
904
  }
859
905
  }
906
+ async installDoclingServeRuntimePackages() {
907
+ const pipPath = (0, import_node_path2.join)(this.venvPath, "bin", "pip");
908
+ const result = await spawnAsync(pipPath, [
909
+ "install",
910
+ "--upgrade",
911
+ ...DOCLING_SERVE_RUNTIME_PACKAGES
912
+ ]);
913
+ if (result.code !== 0) {
914
+ this.logger.error(
915
+ "[DoclingEnvironment] Failed to install docling-serve runtime packages:",
916
+ result.stderr
917
+ );
918
+ throw new Error(
919
+ `Failed to install docling-serve runtime packages. Exit code: ${result.code}`
920
+ );
921
+ }
922
+ }
860
923
  };
861
924
 
862
925
  // src/environment/docling-environment.ts
@@ -3848,6 +3911,7 @@ var PDFParser = class {
3848
3911
  enableImagePdfFallback;
3849
3912
  client = null;
3850
3913
  environment;
3914
+ recoveryPromise = null;
3851
3915
  constructor(options) {
3852
3916
  const {
3853
3917
  logger,
@@ -3932,15 +3996,30 @@ var PDFParser = class {
3932
3996
  */
3933
3997
  isConnectionRefusedError(error) {
3934
3998
  if (error instanceof Error) {
3999
+ const errorWithMetadata = error;
3935
4000
  if (error.message.includes("ECONNREFUSED")) {
3936
4001
  return true;
3937
4002
  }
3938
- if (error.cause instanceof Error && error.cause.message.includes("ECONNREFUSED")) {
4003
+ if (errorWithMetadata.code === "ECONNREFUSED") {
3939
4004
  return true;
3940
4005
  }
4006
+ return this.isConnectionRefusedError(errorWithMetadata.cause);
4007
+ }
4008
+ if (typeof error === "object" && error !== null) {
4009
+ const errorLike = error;
4010
+ if (errorLike.code === "ECONNREFUSED") {
4011
+ return true;
4012
+ }
4013
+ if (typeof errorLike.message === "string" && errorLike.message.includes("ECONNREFUSED")) {
4014
+ return true;
4015
+ }
4016
+ return this.isConnectionRefusedError(errorLike.cause);
3941
4017
  }
3942
4018
  return false;
3943
4019
  }
4020
+ canRecoverLocalServer() {
4021
+ return !this.baseUrl && this.port !== void 0;
4022
+ }
3944
4023
  /**
3945
4024
  * Restart the Docling server after it has crashed.
3946
4025
  * This kills any existing process on the port, starts a new server,
@@ -3970,6 +4049,46 @@ var PDFParser = class {
3970
4049
  await this.waitForServerReady();
3971
4050
  this.logger.info("[PDFParser] Server restarted successfully");
3972
4051
  }
4052
+ async recoverServer(message) {
4053
+ this.logger.warn(message);
4054
+ if (!this.recoveryPromise) {
4055
+ this.recoveryPromise = this.restartServer().finally(() => {
4056
+ this.recoveryPromise = null;
4057
+ });
4058
+ } else {
4059
+ this.logger.warn("[PDFParser] Server recovery already in progress...");
4060
+ }
4061
+ await this.recoveryPromise;
4062
+ }
4063
+ async isReady() {
4064
+ if (!this.client) {
4065
+ return false;
4066
+ }
4067
+ try {
4068
+ await this.client.health();
4069
+ return true;
4070
+ } catch {
4071
+ return false;
4072
+ }
4073
+ }
4074
+ async ensureReady() {
4075
+ if (!this.client) {
4076
+ throw new Error(
4077
+ "PDFParser is not initialized. Call init() before checking readiness"
4078
+ );
4079
+ }
4080
+ try {
4081
+ await this.client.health();
4082
+ } catch (error) {
4083
+ if (this.canRecoverLocalServer()) {
4084
+ await this.recoverServer(
4085
+ "[PDFParser] Health check failed, attempting server recovery..."
4086
+ );
4087
+ return;
4088
+ }
4089
+ throw error;
4090
+ }
4091
+ }
3973
4092
  async waitForServerReady() {
3974
4093
  const maxAttempts = PDF_PARSER.MAX_HEALTH_CHECK_ATTEMPTS;
3975
4094
  const checkInterval = PDF_PARSER.HEALTH_CHECK_INTERVAL_MS;
@@ -4053,18 +4172,16 @@ var PDFParser = class {
4053
4172
  * Recovery is only attempted in local server mode (no baseUrl, port defined).
4054
4173
  */
4055
4174
  async executeWithRecovery(fn, abortSignal) {
4056
- const canRecover = !this.baseUrl && this.port !== void 0;
4057
4175
  const maxAttempts = PDF_PARSER.MAX_SERVER_RECOVERY_ATTEMPTS;
4058
4176
  const tryExecute = async (attempt) => {
4059
4177
  try {
4060
4178
  return await fn();
4061
4179
  } catch (error) {
4062
4180
  if (abortSignal?.aborted) throw error;
4063
- if (canRecover && this.isConnectionRefusedError(error) && attempt < maxAttempts) {
4064
- this.logger.warn(
4181
+ if (this.canRecoverLocalServer() && this.isConnectionRefusedError(error) && attempt < maxAttempts) {
4182
+ await this.recoverServer(
4065
4183
  "[PDFParser] Connection refused, attempting server recovery..."
4066
4184
  );
4067
- await this.restartServer();
4068
4185
  return tryExecute(attempt + 1);
4069
4186
  }
4070
4187
  throw error;