@heripo/pdf-parser 0.1.24 → 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.d.cts CHANGED
@@ -130,6 +130,7 @@ declare class PDFParser {
130
130
  private readonly enableImagePdfFallback;
131
131
  private client;
132
132
  private environment?;
133
+ private recoveryPromise;
133
134
  constructor(options: Options);
134
135
  init(): Promise<void>;
135
136
  /**
@@ -137,6 +138,7 @@ declare class PDFParser {
137
138
  * This typically indicates the Docling server has crashed.
138
139
  */
139
140
  private isConnectionRefusedError;
141
+ private canRecoverLocalServer;
140
142
  /**
141
143
  * Restart the Docling server after it has crashed.
142
144
  * This kills any existing process on the port, starts a new server,
@@ -146,6 +148,9 @@ declare class PDFParser {
146
148
  * which guarantees this.port is defined.
147
149
  */
148
150
  private restartServer;
151
+ private recoverServer;
152
+ isReady(): Promise<boolean>;
153
+ ensureReady(): Promise<void>;
149
154
  private waitForServerReady;
150
155
  parse(url: string, reportId: string, onComplete: ConversionCompleteCallback, cleanupAfterCallback: boolean, options: PDFConvertOptions, abortSignal?: AbortSignal): Promise<TokenUsageReport | null>;
151
156
  /**
package/dist/index.d.ts CHANGED
@@ -130,6 +130,7 @@ declare class PDFParser {
130
130
  private readonly enableImagePdfFallback;
131
131
  private client;
132
132
  private environment?;
133
+ private recoveryPromise;
133
134
  constructor(options: Options);
134
135
  init(): Promise<void>;
135
136
  /**
@@ -137,6 +138,7 @@ declare class PDFParser {
137
138
  * This typically indicates the Docling server has crashed.
138
139
  */
139
140
  private isConnectionRefusedError;
141
+ private canRecoverLocalServer;
140
142
  /**
141
143
  * Restart the Docling server after it has crashed.
142
144
  * This kills any existing process on the port, starts a new server,
@@ -146,6 +148,9 @@ declare class PDFParser {
146
148
  * which guarantees this.port is defined.
147
149
  */
148
150
  private restartServer;
151
+ private recoverServer;
152
+ isReady(): Promise<boolean>;
153
+ ensureReady(): Promise<void>;
149
154
  private waitForServerReady;
150
155
  parse(url: string, reportId: string, onComplete: ConversionCompleteCallback, cleanupAfterCallback: boolean, options: PDFConvertOptions, abortSignal?: AbortSignal): Promise<TokenUsageReport | null>;
151
156
  /**
package/dist/index.js CHANGED
@@ -703,14 +703,32 @@ function validatePythonVersion(version, context = "system") {
703
703
  }
704
704
 
705
705
  // src/environment/python-environment.ts
706
+ var DOCLING_SERVE_PACKAGE = "docling-serve==1.16.1";
706
707
  var DOCLING_RUNTIME_PACKAGES = [
707
- "docling-serve==1.16.1",
708
- "docling-jobkit==1.17.0",
709
- "docling==2.90.0",
710
- "docling-core==2.74.0",
708
+ "docling-jobkit==1.16.0",
709
+ "docling==2.88.0",
710
+ "docling-core==2.73.0",
711
711
  "docling-ibm-models==3.13.0",
712
712
  "docling-parse==5.9.0"
713
713
  ];
714
+ var DOCLING_SERVE_RUNTIME_PACKAGES = [
715
+ "fastapi[standard]<0.130.0",
716
+ "httpx~=0.28",
717
+ "pydantic~=2.10",
718
+ "pydantic-settings~=2.4",
719
+ "python-multipart<0.1.0,>=0.0.14",
720
+ "typer~=0.12",
721
+ "uvicorn[standard]<1.0.0,>=0.29.0",
722
+ "websockets<17.0,>=14.0",
723
+ "scalar-fastapi>=1.0.3",
724
+ "docling-mcp>=1.0.0",
725
+ "opentelemetry-api==1.36.0",
726
+ "opentelemetry-sdk==1.36.0",
727
+ "opentelemetry-exporter-otlp==1.36.0",
728
+ "opentelemetry-instrumentation-fastapi==0.57b0",
729
+ "opentelemetry-exporter-prometheus==0.57b0",
730
+ "prometheus-client>=0.21.0"
731
+ ];
714
732
  var PythonEnvironment = class {
715
733
  constructor(logger, venvPath) {
716
734
  this.logger = logger;
@@ -722,6 +740,8 @@ var PythonEnvironment = class {
722
740
  await this.upgradePip();
723
741
  await this.installSetuptools();
724
742
  await this.installPyArrow();
743
+ await this.installDoclingRuntimePackages();
744
+ await this.installDoclingServeRuntimePackages();
725
745
  await this.installDoclingServe();
726
746
  }
727
747
  async checkPythonVersion() {
@@ -815,13 +835,31 @@ var PythonEnvironment = class {
815
835
  throw new Error(`Failed to install pyarrow. Exit code: ${result.code}`);
816
836
  }
817
837
  }
818
- async installDoclingServe() {
838
+ async installDoclingRuntimePackages() {
819
839
  const pipPath = join2(this.venvPath, "bin", "pip");
820
840
  const result = await spawnAsync(pipPath, [
821
841
  "install",
822
842
  "--upgrade",
823
843
  ...DOCLING_RUNTIME_PACKAGES
824
844
  ]);
845
+ if (result.code !== 0) {
846
+ this.logger.error(
847
+ "[DoclingEnvironment] Failed to install docling runtime packages:",
848
+ result.stderr
849
+ );
850
+ throw new Error(
851
+ `Failed to install docling runtime packages. Exit code: ${result.code}`
852
+ );
853
+ }
854
+ }
855
+ async installDoclingServe() {
856
+ const pipPath = join2(this.venvPath, "bin", "pip");
857
+ const result = await spawnAsync(pipPath, [
858
+ "install",
859
+ "--upgrade",
860
+ "--no-deps",
861
+ DOCLING_SERVE_PACKAGE
862
+ ]);
825
863
  if (result.code !== 0) {
826
864
  this.logger.error(
827
865
  "[DoclingEnvironment] Failed to install docling-serve:",
@@ -832,6 +870,23 @@ var PythonEnvironment = class {
832
870
  );
833
871
  }
834
872
  }
873
+ async installDoclingServeRuntimePackages() {
874
+ const pipPath = join2(this.venvPath, "bin", "pip");
875
+ const result = await spawnAsync(pipPath, [
876
+ "install",
877
+ "--upgrade",
878
+ ...DOCLING_SERVE_RUNTIME_PACKAGES
879
+ ]);
880
+ if (result.code !== 0) {
881
+ this.logger.error(
882
+ "[DoclingEnvironment] Failed to install docling-serve runtime packages:",
883
+ result.stderr
884
+ );
885
+ throw new Error(
886
+ `Failed to install docling-serve runtime packages. Exit code: ${result.code}`
887
+ );
888
+ }
889
+ }
835
890
  };
836
891
 
837
892
  // src/environment/docling-environment.ts
@@ -3839,6 +3894,7 @@ var PDFParser = class {
3839
3894
  enableImagePdfFallback;
3840
3895
  client = null;
3841
3896
  environment;
3897
+ recoveryPromise = null;
3842
3898
  constructor(options) {
3843
3899
  const {
3844
3900
  logger,
@@ -3923,15 +3979,30 @@ var PDFParser = class {
3923
3979
  */
3924
3980
  isConnectionRefusedError(error) {
3925
3981
  if (error instanceof Error) {
3982
+ const errorWithMetadata = error;
3926
3983
  if (error.message.includes("ECONNREFUSED")) {
3927
3984
  return true;
3928
3985
  }
3929
- if (error.cause instanceof Error && error.cause.message.includes("ECONNREFUSED")) {
3986
+ if (errorWithMetadata.code === "ECONNREFUSED") {
3930
3987
  return true;
3931
3988
  }
3989
+ return this.isConnectionRefusedError(errorWithMetadata.cause);
3990
+ }
3991
+ if (typeof error === "object" && error !== null) {
3992
+ const errorLike = error;
3993
+ if (errorLike.code === "ECONNREFUSED") {
3994
+ return true;
3995
+ }
3996
+ if (typeof errorLike.message === "string" && errorLike.message.includes("ECONNREFUSED")) {
3997
+ return true;
3998
+ }
3999
+ return this.isConnectionRefusedError(errorLike.cause);
3932
4000
  }
3933
4001
  return false;
3934
4002
  }
4003
+ canRecoverLocalServer() {
4004
+ return !this.baseUrl && this.port !== void 0;
4005
+ }
3935
4006
  /**
3936
4007
  * Restart the Docling server after it has crashed.
3937
4008
  * This kills any existing process on the port, starts a new server,
@@ -3961,6 +4032,46 @@ var PDFParser = class {
3961
4032
  await this.waitForServerReady();
3962
4033
  this.logger.info("[PDFParser] Server restarted successfully");
3963
4034
  }
4035
+ async recoverServer(message) {
4036
+ this.logger.warn(message);
4037
+ if (!this.recoveryPromise) {
4038
+ this.recoveryPromise = this.restartServer().finally(() => {
4039
+ this.recoveryPromise = null;
4040
+ });
4041
+ } else {
4042
+ this.logger.warn("[PDFParser] Server recovery already in progress...");
4043
+ }
4044
+ await this.recoveryPromise;
4045
+ }
4046
+ async isReady() {
4047
+ if (!this.client) {
4048
+ return false;
4049
+ }
4050
+ try {
4051
+ await this.client.health();
4052
+ return true;
4053
+ } catch {
4054
+ return false;
4055
+ }
4056
+ }
4057
+ async ensureReady() {
4058
+ if (!this.client) {
4059
+ throw new Error(
4060
+ "PDFParser is not initialized. Call init() before checking readiness"
4061
+ );
4062
+ }
4063
+ try {
4064
+ await this.client.health();
4065
+ } catch (error) {
4066
+ if (this.canRecoverLocalServer()) {
4067
+ await this.recoverServer(
4068
+ "[PDFParser] Health check failed, attempting server recovery..."
4069
+ );
4070
+ return;
4071
+ }
4072
+ throw error;
4073
+ }
4074
+ }
3964
4075
  async waitForServerReady() {
3965
4076
  const maxAttempts = PDF_PARSER.MAX_HEALTH_CHECK_ATTEMPTS;
3966
4077
  const checkInterval = PDF_PARSER.HEALTH_CHECK_INTERVAL_MS;
@@ -4044,18 +4155,16 @@ var PDFParser = class {
4044
4155
  * Recovery is only attempted in local server mode (no baseUrl, port defined).
4045
4156
  */
4046
4157
  async executeWithRecovery(fn, abortSignal) {
4047
- const canRecover = !this.baseUrl && this.port !== void 0;
4048
4158
  const maxAttempts = PDF_PARSER.MAX_SERVER_RECOVERY_ATTEMPTS;
4049
4159
  const tryExecute = async (attempt) => {
4050
4160
  try {
4051
4161
  return await fn();
4052
4162
  } catch (error) {
4053
4163
  if (abortSignal?.aborted) throw error;
4054
- if (canRecover && this.isConnectionRefusedError(error) && attempt < maxAttempts) {
4055
- this.logger.warn(
4164
+ if (this.canRecoverLocalServer() && this.isConnectionRefusedError(error) && attempt < maxAttempts) {
4165
+ await this.recoverServer(
4056
4166
  "[PDFParser] Connection refused, attempting server recovery..."
4057
4167
  );
4058
- await this.restartServer();
4059
4168
  return tryExecute(attempt + 1);
4060
4169
  }
4061
4170
  throw error;