@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.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,6 +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";
707
+ var DOCLING_RUNTIME_PACKAGES = [
708
+ "docling-jobkit==1.16.0",
709
+ "docling==2.88.0",
710
+ "docling-core==2.73.0",
711
+ "docling-ibm-models==3.13.0",
712
+ "docling-parse==5.9.0"
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
+ ];
706
732
  var PythonEnvironment = class {
707
733
  constructor(logger, venvPath) {
708
734
  this.logger = logger;
@@ -714,6 +740,8 @@ var PythonEnvironment = class {
714
740
  await this.upgradePip();
715
741
  await this.installSetuptools();
716
742
  await this.installPyArrow();
743
+ await this.installDoclingRuntimePackages();
744
+ await this.installDoclingServeRuntimePackages();
717
745
  await this.installDoclingServe();
718
746
  }
719
747
  async checkPythonVersion() {
@@ -807,12 +835,30 @@ var PythonEnvironment = class {
807
835
  throw new Error(`Failed to install pyarrow. Exit code: ${result.code}`);
808
836
  }
809
837
  }
838
+ async installDoclingRuntimePackages() {
839
+ const pipPath = join2(this.venvPath, "bin", "pip");
840
+ const result = await spawnAsync(pipPath, [
841
+ "install",
842
+ "--upgrade",
843
+ ...DOCLING_RUNTIME_PACKAGES
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
+ }
810
855
  async installDoclingServe() {
811
856
  const pipPath = join2(this.venvPath, "bin", "pip");
812
857
  const result = await spawnAsync(pipPath, [
813
858
  "install",
814
859
  "--upgrade",
815
- "docling-serve"
860
+ "--no-deps",
861
+ DOCLING_SERVE_PACKAGE
816
862
  ]);
817
863
  if (result.code !== 0) {
818
864
  this.logger.error(
@@ -824,6 +870,23 @@ var PythonEnvironment = class {
824
870
  );
825
871
  }
826
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
+ }
827
890
  };
828
891
 
829
892
  // src/environment/docling-environment.ts
@@ -3831,6 +3894,7 @@ var PDFParser = class {
3831
3894
  enableImagePdfFallback;
3832
3895
  client = null;
3833
3896
  environment;
3897
+ recoveryPromise = null;
3834
3898
  constructor(options) {
3835
3899
  const {
3836
3900
  logger,
@@ -3915,15 +3979,30 @@ var PDFParser = class {
3915
3979
  */
3916
3980
  isConnectionRefusedError(error) {
3917
3981
  if (error instanceof Error) {
3982
+ const errorWithMetadata = error;
3918
3983
  if (error.message.includes("ECONNREFUSED")) {
3919
3984
  return true;
3920
3985
  }
3921
- if (error.cause instanceof Error && error.cause.message.includes("ECONNREFUSED")) {
3986
+ if (errorWithMetadata.code === "ECONNREFUSED") {
3922
3987
  return true;
3923
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);
3924
4000
  }
3925
4001
  return false;
3926
4002
  }
4003
+ canRecoverLocalServer() {
4004
+ return !this.baseUrl && this.port !== void 0;
4005
+ }
3927
4006
  /**
3928
4007
  * Restart the Docling server after it has crashed.
3929
4008
  * This kills any existing process on the port, starts a new server,
@@ -3953,6 +4032,46 @@ var PDFParser = class {
3953
4032
  await this.waitForServerReady();
3954
4033
  this.logger.info("[PDFParser] Server restarted successfully");
3955
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
+ }
3956
4075
  async waitForServerReady() {
3957
4076
  const maxAttempts = PDF_PARSER.MAX_HEALTH_CHECK_ATTEMPTS;
3958
4077
  const checkInterval = PDF_PARSER.HEALTH_CHECK_INTERVAL_MS;
@@ -4036,18 +4155,16 @@ var PDFParser = class {
4036
4155
  * Recovery is only attempted in local server mode (no baseUrl, port defined).
4037
4156
  */
4038
4157
  async executeWithRecovery(fn, abortSignal) {
4039
- const canRecover = !this.baseUrl && this.port !== void 0;
4040
4158
  const maxAttempts = PDF_PARSER.MAX_SERVER_RECOVERY_ATTEMPTS;
4041
4159
  const tryExecute = async (attempt) => {
4042
4160
  try {
4043
4161
  return await fn();
4044
4162
  } catch (error) {
4045
4163
  if (abortSignal?.aborted) throw error;
4046
- if (canRecover && this.isConnectionRefusedError(error) && attempt < maxAttempts) {
4047
- this.logger.warn(
4164
+ if (this.canRecoverLocalServer() && this.isConnectionRefusedError(error) && attempt < maxAttempts) {
4165
+ await this.recoverServer(
4048
4166
  "[PDFParser] Connection refused, attempting server recovery..."
4049
4167
  );
4050
- await this.restartServer();
4051
4168
  return tryExecute(attempt + 1);
4052
4169
  }
4053
4170
  throw error;