oxpdf 0.1.1 → 0.1.3
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/README.md +15 -3
- package/dist/index.cjs +86 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -2
- package/dist/index.d.ts +55 -2
- package/dist/index.js +86 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# oxpdf
|
|
2
2
|
|
|
3
|
-
TypeScript/JavaScript SDK for the [0xPdf](https://0xpdf.
|
|
3
|
+
TypeScript/JavaScript SDK for the [0xPdf](https://0xpdf.io) PDF-to-JSON API.
|
|
4
4
|
|
|
5
5
|
Works in **Node.js 18+**, **Bun**, **Deno**, and the **browser** — zero dependencies, uses native `fetch`.
|
|
6
6
|
|
|
@@ -28,6 +28,16 @@ const result2 = await client.parseFile("./invoice.pdf", {
|
|
|
28
28
|
schemaTemplate: "invoice",
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
// Queue async processing and wait for completion
|
|
32
|
+
const queued = await client.upload(pdfBuffer, "invoice.pdf", {
|
|
33
|
+
schemaId: "your_schema_id",
|
|
34
|
+
});
|
|
35
|
+
const finalStatus = await client.waitForJob(queued.job_id, {
|
|
36
|
+
intervalMs: 2000,
|
|
37
|
+
timeoutMs: 180000,
|
|
38
|
+
});
|
|
39
|
+
console.log(finalStatus.status);
|
|
40
|
+
|
|
31
41
|
// Streaming parse with real-time progress
|
|
32
42
|
for await (const event of client.parseFileStream("./large.pdf", {
|
|
33
43
|
schemaTemplate: "invoice",
|
|
@@ -71,14 +81,15 @@ try {
|
|
|
71
81
|
### Constructor
|
|
72
82
|
|
|
73
83
|
```typescript
|
|
74
|
-
new OxPDFClient({ apiKey, baseUrl?, timeout? })
|
|
84
|
+
new OxPDFClient({ apiKey, baseUrl?, timeout?, retry? })
|
|
75
85
|
```
|
|
76
86
|
|
|
77
87
|
| Option | Type | Default | Description |
|
|
78
88
|
| --------- | -------- | ------------------------------------ | -------------------- |
|
|
79
89
|
| `apiKey` | `string` | — | Your 0xPdf API key |
|
|
80
|
-
| `baseUrl` | `string` | `https://api.0xpdf.
|
|
90
|
+
| `baseUrl` | `string` | `https://api.0xpdf.io/api/v1` | API base URL |
|
|
81
91
|
| `timeout` | `number` | `120000` | Request timeout (ms) |
|
|
92
|
+
| `retry` | `object` | `{ maxRetries: 2, initialDelayMs: 500, backoffMultiplier: 2 }` | Retry/backoff config |
|
|
82
93
|
|
|
83
94
|
### PDF Parsing
|
|
84
95
|
|
|
@@ -96,6 +107,7 @@ new OxPDFClient({ apiKey, baseUrl?, timeout? })
|
|
|
96
107
|
|---|---|
|
|
97
108
|
| `upload(file, filename, options?)` | Queue PDF for background processing |
|
|
98
109
|
| `jobStatus(jobId)` | Poll async job status |
|
|
110
|
+
| `waitForJob(jobId, options?)` | Poll until `completed`/`failed` (with timeout) |
|
|
99
111
|
|
|
100
112
|
### Image Extraction
|
|
101
113
|
|
package/dist/index.cjs
CHANGED
|
@@ -48,12 +48,21 @@ var OxPDFError = class extends Error {
|
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
// src/client.ts
|
|
51
|
-
var DEFAULT_BASE_URL = "https://api.0xpdf.
|
|
51
|
+
var DEFAULT_BASE_URL = "https://api.0xpdf.io/api/v1";
|
|
52
52
|
var DEFAULT_TIMEOUT = 12e4;
|
|
53
|
+
var DEFAULT_RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];
|
|
54
|
+
var DEFAULT_RETRY = {
|
|
55
|
+
maxRetries: 2,
|
|
56
|
+
initialDelayMs: 500,
|
|
57
|
+
backoffMultiplier: 2,
|
|
58
|
+
retryableStatusCodes: DEFAULT_RETRYABLE_STATUS_CODES
|
|
59
|
+
};
|
|
60
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
53
61
|
var OxPDFClient = class {
|
|
54
62
|
#apiKey;
|
|
55
63
|
#baseUrl;
|
|
56
64
|
#timeout;
|
|
65
|
+
#retry;
|
|
57
66
|
constructor(options) {
|
|
58
67
|
if (!options.apiKey) {
|
|
59
68
|
throw new OxPDFError("apiKey is required");
|
|
@@ -61,6 +70,12 @@ var OxPDFClient = class {
|
|
|
61
70
|
this.#apiKey = options.apiKey;
|
|
62
71
|
this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
63
72
|
this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
73
|
+
this.#retry = {
|
|
74
|
+
maxRetries: options.retry?.maxRetries ?? DEFAULT_RETRY.maxRetries,
|
|
75
|
+
initialDelayMs: options.retry?.initialDelayMs ?? DEFAULT_RETRY.initialDelayMs,
|
|
76
|
+
backoffMultiplier: options.retry?.backoffMultiplier ?? DEFAULT_RETRY.backoffMultiplier,
|
|
77
|
+
retryableStatusCodes: options.retry?.retryableStatusCodes ?? DEFAULT_RETRY.retryableStatusCodes
|
|
78
|
+
};
|
|
64
79
|
}
|
|
65
80
|
// ── internal helpers ─────────────────────────────────────────────
|
|
66
81
|
#url(path) {
|
|
@@ -73,45 +88,59 @@ var OxPDFClient = class {
|
|
|
73
88
|
url.searchParams.set(k, v);
|
|
74
89
|
}
|
|
75
90
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
resp = await fetch(url.toString(), {
|
|
81
|
-
method,
|
|
82
|
-
headers: {
|
|
83
|
-
"X-API-Key": this.#apiKey,
|
|
84
|
-
...init?.headers
|
|
85
|
-
},
|
|
86
|
-
body: init?.body,
|
|
87
|
-
signal: controller.signal
|
|
88
|
-
});
|
|
89
|
-
} catch (err) {
|
|
90
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
91
|
-
throw new OxPDFError(`Request failed: ${msg}`);
|
|
92
|
-
} finally {
|
|
93
|
-
clearTimeout(timer);
|
|
94
|
-
}
|
|
95
|
-
if (resp.status === 204) return {};
|
|
96
|
-
if (!resp.ok) {
|
|
97
|
-
const text2 = await resp.text();
|
|
98
|
-
let detail;
|
|
91
|
+
for (let attempt = 0; attempt <= this.#retry.maxRetries; attempt++) {
|
|
92
|
+
const controller = new AbortController();
|
|
93
|
+
const timer = setTimeout(() => controller.abort(), this.#timeout);
|
|
94
|
+
let resp;
|
|
99
95
|
try {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
96
|
+
resp = await fetch(url.toString(), {
|
|
97
|
+
method,
|
|
98
|
+
headers: {
|
|
99
|
+
"X-API-Key": this.#apiKey,
|
|
100
|
+
...init?.headers
|
|
101
|
+
},
|
|
102
|
+
body: init?.body,
|
|
103
|
+
signal: controller.signal
|
|
104
|
+
});
|
|
105
|
+
} catch (err) {
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
if (attempt < this.#retry.maxRetries) {
|
|
108
|
+
const delay = this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);
|
|
109
|
+
await sleep(delay);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
113
|
+
throw new OxPDFError(`Request failed: ${msg}`);
|
|
114
|
+
} finally {
|
|
115
|
+
clearTimeout(timer);
|
|
116
|
+
}
|
|
117
|
+
if (resp.status === 204) return {};
|
|
118
|
+
if (!resp.ok) {
|
|
119
|
+
const text2 = await resp.text();
|
|
120
|
+
if (this.#retry.retryableStatusCodes.includes(resp.status) && attempt < this.#retry.maxRetries) {
|
|
121
|
+
const delay = this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);
|
|
122
|
+
await sleep(delay);
|
|
123
|
+
continue;
|
|
106
124
|
}
|
|
107
|
-
|
|
108
|
-
|
|
125
|
+
let detail;
|
|
126
|
+
try {
|
|
127
|
+
const body = JSON.parse(text2);
|
|
128
|
+
const raw = body.detail ?? body.error ?? text2;
|
|
129
|
+
if (Array.isArray(raw)) {
|
|
130
|
+
detail = raw.map((d) => d.msg ?? JSON.stringify(d)).join("; ");
|
|
131
|
+
} else {
|
|
132
|
+
detail = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
133
|
+
}
|
|
134
|
+
} catch {
|
|
135
|
+
detail = text2 || resp.statusText || `HTTP ${resp.status}`;
|
|
136
|
+
}
|
|
137
|
+
throw new OxPDFError(detail, resp.status, text2);
|
|
109
138
|
}
|
|
110
|
-
|
|
139
|
+
const text = await resp.text();
|
|
140
|
+
if (!text) return {};
|
|
141
|
+
return JSON.parse(text);
|
|
111
142
|
}
|
|
112
|
-
|
|
113
|
-
if (!text) return {};
|
|
114
|
-
return JSON.parse(text);
|
|
143
|
+
throw new OxPDFError("Request failed after retries");
|
|
115
144
|
}
|
|
116
145
|
#buildPdfForm(file, filename, fields) {
|
|
117
146
|
if (!filename.toLowerCase().endsWith(".pdf")) {
|
|
@@ -255,6 +284,27 @@ var OxPDFClient = class {
|
|
|
255
284
|
async jobStatus(jobId) {
|
|
256
285
|
return this.#request("GET", `pdf/status/${jobId}`);
|
|
257
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Wait until an async job reaches a terminal state.
|
|
289
|
+
* Throws on timeout.
|
|
290
|
+
*/
|
|
291
|
+
async waitForJob(jobId, options = {}) {
|
|
292
|
+
const intervalMs = options.intervalMs ?? 2e3;
|
|
293
|
+
const timeoutMs = options.timeoutMs ?? 12e4;
|
|
294
|
+
const startedAt = Date.now();
|
|
295
|
+
while (true) {
|
|
296
|
+
const status = await this.jobStatus(jobId);
|
|
297
|
+
if (status.status === "completed" || status.status === "failed") {
|
|
298
|
+
return status;
|
|
299
|
+
}
|
|
300
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
301
|
+
throw new OxPDFError(
|
|
302
|
+
`Timed out waiting for job ${jobId} after ${timeoutMs}ms`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
await sleep(intervalMs);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
258
308
|
// ── PDF validation ───────────────────────────────────────────────
|
|
259
309
|
/** Validate a PDF without full processing (dry-run). */
|
|
260
310
|
async validate(file, filename, options = {}) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export { OxPDFClient } from \"./client.js\";\nexport { OxPDFError } from \"./errors.js\";\nexport type {\n AnalyticsResult,\n ClientOptions,\n CreateSchemaOptions,\n ExtractImagesOptions,\n FileInfo,\n FileListResult,\n GenerateSchemaOptions,\n GenerateSchemaResult,\n ImageInfo,\n ImageListResult,\n ImageUrlResult,\n JobStatus,\n ParseOptions,\n ParseResult,\n ParseStreamOptions,\n SchemaInfo,\n SchemaTemplate,\n StreamEvent,\n UpdateSchemaOptions,\n UploadOptions,\n UploadResult,\n ValidateOptions,\n} from \"./types.js\";\n","export class OxPDFError extends Error {\n readonly statusCode: number | undefined;\n readonly responseBody: string | undefined;\n\n constructor(\n message: string,\n statusCode?: number,\n responseBody?: string,\n ) {\n super(message);\n this.name = \"OxPDFError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n }\n}\n","import { OxPDFError } from \"./errors.js\";\nimport type {\n AnalyticsResult,\n ClientOptions,\n CreateSchemaOptions,\n ExtractImagesOptions,\n FileInfo,\n FileListResult,\n GenerateSchemaOptions,\n GenerateSchemaResult,\n ImageListResult,\n ImageUrlResult,\n JobStatus,\n ParseOptions,\n ParseResult,\n ParseStreamOptions,\n SchemaInfo,\n SchemaTemplate,\n StreamEvent,\n UpdateSchemaOptions,\n UploadOptions,\n UploadResult,\n ValidateOptions,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.0xpdf.com/api/v1\";\nconst DEFAULT_TIMEOUT = 120_000;\n\nexport class OxPDFClient {\n readonly #apiKey: string;\n readonly #baseUrl: string;\n readonly #timeout: number;\n\n constructor(options: ClientOptions) {\n if (!options.apiKey) {\n throw new OxPDFError(\"apiKey is required\");\n }\n this.#apiKey = options.apiKey;\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;\n }\n\n // ── internal helpers ─────────────────────────────────────────────\n\n #url(path: string): string {\n return `${this.#baseUrl}/${path.replace(/^\\/+/, \"\")}`;\n }\n\n async #request<T = Record<string, unknown>>(\n method: string,\n path: string,\n init?: {\n params?: Record<string, string>;\n body?: FormData | string;\n headers?: Record<string, string>;\n },\n ): Promise<T> {\n const url = new URL(this.#url(path));\n if (init?.params) {\n for (const [k, v] of Object.entries(init.params)) {\n url.searchParams.set(k, v);\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.#timeout);\n\n let resp: Response;\n try {\n resp = await fetch(url.toString(), {\n method,\n headers: {\n \"X-API-Key\": this.#apiKey,\n ...init?.headers,\n },\n body: init?.body,\n signal: controller.signal,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Request failed: ${msg}`);\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 204) return {} as T;\n\n if (!resp.ok) {\n const text = await resp.text();\n let detail: string;\n try {\n const body = JSON.parse(text);\n const raw = body.detail ?? body.error ?? text;\n if (Array.isArray(raw)) {\n detail = raw.map((d: Record<string, unknown>) => d.msg ?? JSON.stringify(d)).join(\"; \");\n } else {\n detail = typeof raw === \"string\" ? raw : JSON.stringify(raw);\n }\n } catch {\n detail = text || resp.statusText || `HTTP ${resp.status}`;\n }\n throw new OxPDFError(detail, resp.status, text);\n }\n\n const text = await resp.text();\n if (!text) return {} as T;\n return JSON.parse(text) as T;\n }\n\n #buildPdfForm(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n fields?: Record<string, string>,\n ): FormData {\n if (!filename.toLowerCase().endsWith(\".pdf\")) {\n throw new OxPDFError(\"File must be a PDF\");\n }\n\n const form = new FormData();\n let blob: Blob;\n if (file instanceof Blob) {\n blob = file;\n } else {\n const arr = new Uint8Array(file.buffer, file.byteOffset, file.byteLength);\n blob = new Blob([arr as unknown as Uint8Array<ArrayBuffer>], {\n type: \"application/pdf\",\n });\n }\n form.append(\"file\", blob, filename);\n if (fields) {\n for (const [k, v] of Object.entries(fields)) form.append(k, v);\n }\n return form;\n }\n\n // ── PDF parsing ──────────────────────────────────────────────────\n\n /** Parse a PDF and return structured JSON. */\n async parse(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseOptions = {},\n ): Promise<ParseResult> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {};\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n return this.#request<ParseResult>(\"POST\", \"pdf/parse\", {\n params: Object.keys(params).length ? params : undefined,\n body: form,\n });\n }\n\n /** Parse a PDF from a file path (Node.js only). */\n async parseFile(filePath: string, options: ParseOptions = {}): Promise<ParseResult> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n return this.parse(buf, basename(filePath), options);\n }\n\n /**\n * Streaming parse via Server-Sent Events.\n * Returns an async generator that yields ``StreamEvent`` objects.\n */\n async *parseStream(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {\n batch_size: String(options.batchSize ?? 5),\n };\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n const url = new URL(this.#url(\"pdf/parse-stream\"));\n for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 300_000);\n\n let resp: Response;\n try {\n resp = await fetch(url.toString(), {\n method: \"POST\",\n headers: { \"X-API-Key\": this.#apiKey },\n body: form,\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Stream request failed: ${msg}`);\n }\n\n if (!resp.ok) {\n clearTimeout(timer);\n const text = await resp.text();\n throw new OxPDFError(text, resp.status, text);\n }\n\n try {\n const reader = resp.body?.getReader();\n if (!reader) throw new OxPDFError(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventType = \"message\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const raw = line.slice(5).trim();\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(raw);\n } catch {\n data = { raw };\n }\n yield { event: eventType, data };\n eventType = \"message\";\n }\n }\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n /** Streaming parse from a file path (Node.js only). */\n async *parseFileStream(\n filePath: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n yield* this.parseStream(buf, basename(filePath), options);\n }\n\n // ── Async upload (job queue) ─────────────────────────────────────\n\n /** Upload a PDF for async background processing. Returns a job_id. */\n async upload(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: UploadOptions = {},\n ): Promise<UploadResult> {\n const params: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n\n return this.#request<UploadResult>(\"POST\", \"pdf/upload\", {\n params,\n body: form,\n });\n }\n\n /** Poll the status of an async PDF processing job. */\n async jobStatus(jobId: string): Promise<JobStatus> {\n return this.#request<JobStatus>(\"GET\", `pdf/status/${jobId}`);\n }\n\n // ── PDF validation ───────────────────────────────────────────────\n\n /** Validate a PDF without full processing (dry-run). */\n async validate(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ValidateOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = { dry_run: \"true\" };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/validate\", { params, body: form });\n }\n\n // ── Image extraction ─────────────────────────────────────────────\n\n /** Extract images from a PDF. */\n async extractImages(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ExtractImagesOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = {\n min_width: String(options.minWidth ?? 50),\n min_height: String(options.minHeight ?? 50),\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/parse-images\", { params, body: form });\n }\n\n // ── Image management ─────────────────────────────────────────────\n\n /** List extracted images. */\n async listImages(limit = 100, offset = 0): Promise<ImageListResult> {\n return this.#request<ImageListResult>(\"GET\", \"pdf/images\", {\n params: { limit: String(limit), offset: String(offset) },\n });\n }\n\n /** Get or refresh a presigned URL for an image. */\n async getImageUrl(imageId: string, expirationSeconds = 3600): Promise<ImageUrlResult> {\n return this.#request<ImageUrlResult>(\"GET\", `pdf/images/${imageId}/url`, {\n params: { expiration_seconds: String(expirationSeconds) },\n });\n }\n\n /** Delete a specific image. */\n async deleteImage(imageId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/images/${imageId}`);\n }\n\n /** Delete all extracted images. */\n async deleteAllImages(): Promise<Record<string, unknown>> {\n return this.#request(\"DELETE\", \"pdf/images\");\n }\n\n // ── File management ──────────────────────────────────────────────\n\n /** List previously uploaded PDFs. */\n async listFiles(): Promise<FileListResult> {\n return this.#request<FileListResult>(\"GET\", \"pdf/files\");\n }\n\n /** Get metadata and download URL for an uploaded PDF. */\n async getFile(pdfId: string): Promise<FileInfo> {\n return this.#request<FileInfo>(\"GET\", `pdf/files/${pdfId}`);\n }\n\n /** Delete an uploaded PDF. */\n async deleteFile(pdfId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/files/${pdfId}`);\n }\n\n // ── Schema templates ─────────────────────────────────────────────\n\n /** List pre-built schema templates (pdf route). */\n async listTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\"GET\", \"pdf/templates\");\n return res.templates ?? [];\n }\n\n /** List schema templates from /schemas/templates/list. */\n async listSchemaTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\n \"GET\",\n \"schemas/templates/list\",\n );\n return res.templates ?? [];\n }\n\n /** Get a specific schema template with full definition. */\n async getSchemaTemplate(templateId: string): Promise<SchemaTemplate> {\n return this.#request<SchemaTemplate>(\"GET\", `schemas/templates/${templateId}`);\n }\n\n // ── Schema CRUD ──────────────────────────────────────────────────\n\n /** List user's saved schemas. */\n async listSchemas(): Promise<SchemaInfo[]> {\n const res = await this.#request<{ schemas: SchemaInfo[] }>(\"GET\", \"schemas\");\n return res.schemas ?? [];\n }\n\n /** Get a specific schema by ID. */\n async getSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"GET\", `schemas/${schemaId}`);\n }\n\n /** Create a new JSON schema. */\n async createSchema(options: CreateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"POST\", \"schemas\", {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Update an existing schema. */\n async updateSchema(schemaId: string, options: UpdateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PUT\", `schemas/${schemaId}`, {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Delete a schema. */\n async deleteSchema(schemaId: string): Promise<void> {\n await this.#request(\"DELETE\", `schemas/${schemaId}`);\n }\n\n /** Set a schema as the default. */\n async setDefaultSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PATCH\", `schemas/${schemaId}/set-default`);\n }\n\n /** Generate a schema using AI from a natural-language description. */\n async generateSchema(options: GenerateSchemaOptions): Promise<GenerateSchemaResult> {\n const body: Record<string, unknown> = { description: options.description };\n if (options.refinement) body.refinement = options.refinement;\n if (options.currentSchema) body.current_schema = options.currentSchema;\n if (options.selectedText) body.selected_text = options.selectedText;\n\n return this.#request<GenerateSchemaResult>(\"POST\", \"schemas/generate\", {\n body: JSON.stringify(body),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Analytics ────────────────────────────────────────────────────\n\n /** Get usage analytics for the current user/org. */\n async getAnalytics(): Promise<AnalyticsResult> {\n return this.#request<AnalyticsResult>(\"GET\", \"analytics/user\");\n }\n\n /** Submit in-app feedback. */\n async submitFeedback(feedback: string): Promise<{ success: boolean }> {\n return this.#request<{ success: boolean }>(\"POST\", \"analytics/feedback\", {\n body: JSON.stringify({ feedback }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Pricing ──────────────────────────────────────────────────────\n\n /** Get available pricing tiers. */\n async getPricing(billingCycle = \"monthly\"): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing\", {\n params: { billing_cycle: billingCycle },\n });\n }\n\n /** Get the current user's tier and quota. */\n async getCurrentTier(): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing/current\");\n }\n}\n"],"mappings":"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","names":["text"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export { OxPDFClient } from \"./client.js\";\nexport { OxPDFError } from \"./errors.js\";\nexport type {\n AnalyticsResult,\n ClientOptions,\n CreateSchemaOptions,\n ExtractImagesOptions,\n FileInfo,\n FileListResult,\n GenerateSchemaOptions,\n GenerateSchemaResult,\n ImageInfo,\n ImageListResult,\n ImageUrlResult,\n JobStatus,\n ParseMetadata,\n ParseOptions,\n ParseResult,\n ParseStreamOptions,\n RetryOptions,\n SchemaInfo,\n SchemaQualityMetadata,\n SchemaValidationError,\n SchemaTemplate,\n StreamEvent,\n UpdateSchemaOptions,\n UploadOptions,\n UploadResult,\n ValidateOptions,\n WaitForJobOptions,\n} from \"./types.js\";\n","export class OxPDFError extends Error {\n readonly statusCode: number | undefined;\n readonly responseBody: string | undefined;\n\n constructor(\n message: string,\n statusCode?: number,\n responseBody?: string,\n ) {\n super(message);\n this.name = \"OxPDFError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n }\n}\n","import { OxPDFError } from \"./errors.js\";\nimport type {\n AnalyticsResult,\n ClientOptions,\n CreateSchemaOptions,\n ExtractImagesOptions,\n FileInfo,\n FileListResult,\n GenerateSchemaOptions,\n GenerateSchemaResult,\n ImageListResult,\n ImageUrlResult,\n JobStatus,\n ParseOptions,\n ParseResult,\n ParseStreamOptions,\n RetryOptions,\n SchemaInfo,\n SchemaTemplate,\n StreamEvent,\n UpdateSchemaOptions,\n UploadOptions,\n UploadResult,\n ValidateOptions,\n WaitForJobOptions,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.0xpdf.io/api/v1\";\nconst DEFAULT_TIMEOUT = 120_000;\nconst DEFAULT_RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];\nconst DEFAULT_RETRY: Required<RetryOptions> = {\n maxRetries: 2,\n initialDelayMs: 500,\n backoffMultiplier: 2,\n retryableStatusCodes: DEFAULT_RETRYABLE_STATUS_CODES,\n};\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport class OxPDFClient {\n readonly #apiKey: string;\n readonly #baseUrl: string;\n readonly #timeout: number;\n readonly #retry: Required<RetryOptions>;\n\n constructor(options: ClientOptions) {\n if (!options.apiKey) {\n throw new OxPDFError(\"apiKey is required\");\n }\n this.#apiKey = options.apiKey;\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;\n this.#retry = {\n maxRetries: options.retry?.maxRetries ?? DEFAULT_RETRY.maxRetries,\n initialDelayMs: options.retry?.initialDelayMs ?? DEFAULT_RETRY.initialDelayMs,\n backoffMultiplier: options.retry?.backoffMultiplier ?? DEFAULT_RETRY.backoffMultiplier,\n retryableStatusCodes:\n options.retry?.retryableStatusCodes ?? DEFAULT_RETRY.retryableStatusCodes,\n };\n }\n\n // ── internal helpers ─────────────────────────────────────────────\n\n #url(path: string): string {\n return `${this.#baseUrl}/${path.replace(/^\\/+/, \"\")}`;\n }\n\n async #request<T = Record<string, unknown>>(\n method: string,\n path: string,\n init?: {\n params?: Record<string, string>;\n body?: FormData | string;\n headers?: Record<string, string>;\n },\n ): Promise<T> {\n const url = new URL(this.#url(path));\n if (init?.params) {\n for (const [k, v] of Object.entries(init.params)) {\n url.searchParams.set(k, v);\n }\n }\n\n for (let attempt = 0; attempt <= this.#retry.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.#timeout);\n let resp: Response;\n\n try {\n resp = await fetch(url.toString(), {\n method,\n headers: {\n \"X-API-Key\": this.#apiKey,\n ...init?.headers,\n },\n body: init?.body,\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n if (attempt < this.#retry.maxRetries) {\n const delay =\n this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);\n await sleep(delay);\n continue;\n }\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Request failed: ${msg}`);\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 204) return {} as T;\n\n if (!resp.ok) {\n const text = await resp.text();\n if (\n this.#retry.retryableStatusCodes.includes(resp.status) &&\n attempt < this.#retry.maxRetries\n ) {\n const delay =\n this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);\n await sleep(delay);\n continue;\n }\n\n let detail: string;\n try {\n const body = JSON.parse(text);\n const raw = body.detail ?? body.error ?? text;\n if (Array.isArray(raw)) {\n detail = raw.map((d: Record<string, unknown>) => d.msg ?? JSON.stringify(d)).join(\"; \");\n } else {\n detail = typeof raw === \"string\" ? raw : JSON.stringify(raw);\n }\n } catch {\n detail = text || resp.statusText || `HTTP ${resp.status}`;\n }\n throw new OxPDFError(detail, resp.status, text);\n }\n\n const text = await resp.text();\n if (!text) return {} as T;\n return JSON.parse(text) as T;\n }\n\n throw new OxPDFError(\"Request failed after retries\");\n }\n\n #buildPdfForm(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n fields?: Record<string, string>,\n ): FormData {\n if (!filename.toLowerCase().endsWith(\".pdf\")) {\n throw new OxPDFError(\"File must be a PDF\");\n }\n\n const form = new FormData();\n let blob: Blob;\n if (file instanceof Blob) {\n blob = file;\n } else {\n const arr = new Uint8Array(file.buffer, file.byteOffset, file.byteLength);\n blob = new Blob([arr as unknown as Uint8Array<ArrayBuffer>], {\n type: \"application/pdf\",\n });\n }\n form.append(\"file\", blob, filename);\n if (fields) {\n for (const [k, v] of Object.entries(fields)) form.append(k, v);\n }\n return form;\n }\n\n // ── PDF parsing ──────────────────────────────────────────────────\n\n /** Parse a PDF and return structured JSON. */\n async parse(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseOptions = {},\n ): Promise<ParseResult> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {};\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n return this.#request<ParseResult>(\"POST\", \"pdf/parse\", {\n params: Object.keys(params).length ? params : undefined,\n body: form,\n });\n }\n\n /** Parse a PDF from a file path (Node.js only). */\n async parseFile(filePath: string, options: ParseOptions = {}): Promise<ParseResult> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n return this.parse(buf, basename(filePath), options);\n }\n\n /**\n * Streaming parse via Server-Sent Events.\n * Returns an async generator that yields ``StreamEvent`` objects.\n */\n async *parseStream(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {\n batch_size: String(options.batchSize ?? 5),\n };\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n const url = new URL(this.#url(\"pdf/parse-stream\"));\n for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 300_000);\n\n let resp: Response;\n try {\n resp = await fetch(url.toString(), {\n method: \"POST\",\n headers: { \"X-API-Key\": this.#apiKey },\n body: form,\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Stream request failed: ${msg}`);\n }\n\n if (!resp.ok) {\n clearTimeout(timer);\n const text = await resp.text();\n throw new OxPDFError(text, resp.status, text);\n }\n\n try {\n const reader = resp.body?.getReader();\n if (!reader) throw new OxPDFError(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventType = \"message\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const raw = line.slice(5).trim();\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(raw);\n } catch {\n data = { raw };\n }\n yield { event: eventType, data };\n eventType = \"message\";\n }\n }\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n /** Streaming parse from a file path (Node.js only). */\n async *parseFileStream(\n filePath: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n yield* this.parseStream(buf, basename(filePath), options);\n }\n\n // ── Async upload (job queue) ─────────────────────────────────────\n\n /** Upload a PDF for async background processing. Returns a job_id. */\n async upload(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: UploadOptions = {},\n ): Promise<UploadResult> {\n const params: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n\n return this.#request<UploadResult>(\"POST\", \"pdf/upload\", {\n params,\n body: form,\n });\n }\n\n /** Poll the status of an async PDF processing job. */\n async jobStatus(jobId: string): Promise<JobStatus> {\n return this.#request<JobStatus>(\"GET\", `pdf/status/${jobId}`);\n }\n\n /**\n * Wait until an async job reaches a terminal state.\n * Throws on timeout.\n */\n async waitForJob(jobId: string, options: WaitForJobOptions = {}): Promise<JobStatus> {\n const intervalMs = options.intervalMs ?? 2_000;\n const timeoutMs = options.timeoutMs ?? 120_000;\n const startedAt = Date.now();\n\n while (true) {\n const status = await this.jobStatus(jobId);\n if (status.status === \"completed\" || status.status === \"failed\") {\n return status;\n }\n if (Date.now() - startedAt > timeoutMs) {\n throw new OxPDFError(\n `Timed out waiting for job ${jobId} after ${timeoutMs}ms`,\n );\n }\n await sleep(intervalMs);\n }\n }\n\n // ── PDF validation ───────────────────────────────────────────────\n\n /** Validate a PDF without full processing (dry-run). */\n async validate(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ValidateOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = { dry_run: \"true\" };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/validate\", { params, body: form });\n }\n\n // ── Image extraction ─────────────────────────────────────────────\n\n /** Extract images from a PDF. */\n async extractImages(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ExtractImagesOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = {\n min_width: String(options.minWidth ?? 50),\n min_height: String(options.minHeight ?? 50),\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/parse-images\", { params, body: form });\n }\n\n // ── Image management ─────────────────────────────────────────────\n\n /** List extracted images. */\n async listImages(limit = 100, offset = 0): Promise<ImageListResult> {\n return this.#request<ImageListResult>(\"GET\", \"pdf/images\", {\n params: { limit: String(limit), offset: String(offset) },\n });\n }\n\n /** Get or refresh a presigned URL for an image. */\n async getImageUrl(imageId: string, expirationSeconds = 3600): Promise<ImageUrlResult> {\n return this.#request<ImageUrlResult>(\"GET\", `pdf/images/${imageId}/url`, {\n params: { expiration_seconds: String(expirationSeconds) },\n });\n }\n\n /** Delete a specific image. */\n async deleteImage(imageId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/images/${imageId}`);\n }\n\n /** Delete all extracted images. */\n async deleteAllImages(): Promise<Record<string, unknown>> {\n return this.#request(\"DELETE\", \"pdf/images\");\n }\n\n // ── File management ──────────────────────────────────────────────\n\n /** List previously uploaded PDFs. */\n async listFiles(): Promise<FileListResult> {\n return this.#request<FileListResult>(\"GET\", \"pdf/files\");\n }\n\n /** Get metadata and download URL for an uploaded PDF. */\n async getFile(pdfId: string): Promise<FileInfo> {\n return this.#request<FileInfo>(\"GET\", `pdf/files/${pdfId}`);\n }\n\n /** Delete an uploaded PDF. */\n async deleteFile(pdfId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/files/${pdfId}`);\n }\n\n // ── Schema templates ─────────────────────────────────────────────\n\n /** List pre-built schema templates (pdf route). */\n async listTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\"GET\", \"pdf/templates\");\n return res.templates ?? [];\n }\n\n /** List schema templates from /schemas/templates/list. */\n async listSchemaTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\n \"GET\",\n \"schemas/templates/list\",\n );\n return res.templates ?? [];\n }\n\n /** Get a specific schema template with full definition. */\n async getSchemaTemplate(templateId: string): Promise<SchemaTemplate> {\n return this.#request<SchemaTemplate>(\"GET\", `schemas/templates/${templateId}`);\n }\n\n // ── Schema CRUD ──────────────────────────────────────────────────\n\n /** List user's saved schemas. */\n async listSchemas(): Promise<SchemaInfo[]> {\n const res = await this.#request<{ schemas: SchemaInfo[] }>(\"GET\", \"schemas\");\n return res.schemas ?? [];\n }\n\n /** Get a specific schema by ID. */\n async getSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"GET\", `schemas/${schemaId}`);\n }\n\n /** Create a new JSON schema. */\n async createSchema(options: CreateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"POST\", \"schemas\", {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Update an existing schema. */\n async updateSchema(schemaId: string, options: UpdateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PUT\", `schemas/${schemaId}`, {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Delete a schema. */\n async deleteSchema(schemaId: string): Promise<void> {\n await this.#request(\"DELETE\", `schemas/${schemaId}`);\n }\n\n /** Set a schema as the default. */\n async setDefaultSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PATCH\", `schemas/${schemaId}/set-default`);\n }\n\n /** Generate a schema using AI from a natural-language description. */\n async generateSchema(options: GenerateSchemaOptions): Promise<GenerateSchemaResult> {\n const body: Record<string, unknown> = { description: options.description };\n if (options.refinement) body.refinement = options.refinement;\n if (options.currentSchema) body.current_schema = options.currentSchema;\n if (options.selectedText) body.selected_text = options.selectedText;\n\n return this.#request<GenerateSchemaResult>(\"POST\", \"schemas/generate\", {\n body: JSON.stringify(body),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Analytics ────────────────────────────────────────────────────\n\n /** Get usage analytics for the current user/org. */\n async getAnalytics(): Promise<AnalyticsResult> {\n return this.#request<AnalyticsResult>(\"GET\", \"analytics/user\");\n }\n\n /** Submit in-app feedback. */\n async submitFeedback(feedback: string): Promise<{ success: boolean }> {\n return this.#request<{ success: boolean }>(\"POST\", \"analytics/feedback\", {\n body: JSON.stringify({ feedback }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Pricing ──────────────────────────────────────────────────────\n\n /** Get available pricing tiers. */\n async getPricing(billingCycle = \"monthly\"): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing\", {\n params: { billing_cycle: billingCycle },\n });\n }\n\n /** Get the current user's tier and quota. */\n async getCurrentTier(): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing/current\");\n }\n}\n"],"mappings":"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","names":["text"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -3,6 +3,24 @@ interface ClientOptions {
|
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
/** Request timeout in milliseconds (default: 120_000) */
|
|
5
5
|
timeout?: number;
|
|
6
|
+
/** Retry settings for transient failures (network, 429, 5xx). */
|
|
7
|
+
retry?: RetryOptions;
|
|
8
|
+
}
|
|
9
|
+
interface RetryOptions {
|
|
10
|
+
/** Maximum retries per request (default: 2). */
|
|
11
|
+
maxRetries?: number;
|
|
12
|
+
/** Initial backoff delay in milliseconds (default: 500). */
|
|
13
|
+
initialDelayMs?: number;
|
|
14
|
+
/** Multiplier applied on each retry (default: 2). */
|
|
15
|
+
backoffMultiplier?: number;
|
|
16
|
+
/** HTTP statuses to retry (default: 429, 500, 502, 503, 504). */
|
|
17
|
+
retryableStatusCodes?: number[];
|
|
18
|
+
}
|
|
19
|
+
interface WaitForJobOptions {
|
|
20
|
+
/** Poll interval in milliseconds (default: 2000). */
|
|
21
|
+
intervalMs?: number;
|
|
22
|
+
/** Overall timeout in milliseconds (default: 120000). */
|
|
23
|
+
timeoutMs?: number;
|
|
6
24
|
}
|
|
7
25
|
interface ParseOptions {
|
|
8
26
|
schema?: Record<string, unknown>;
|
|
@@ -19,11 +37,41 @@ interface ParseResult {
|
|
|
19
37
|
success: boolean;
|
|
20
38
|
data?: Record<string, unknown>;
|
|
21
39
|
error?: string;
|
|
22
|
-
metadata?:
|
|
40
|
+
metadata?: ParseMetadata;
|
|
23
41
|
cached?: boolean;
|
|
24
42
|
quota?: Record<string, unknown>;
|
|
25
43
|
[key: string]: unknown;
|
|
26
44
|
}
|
|
45
|
+
interface SchemaValidationError {
|
|
46
|
+
path: string;
|
|
47
|
+
expected: string[];
|
|
48
|
+
actual: string;
|
|
49
|
+
message: string;
|
|
50
|
+
}
|
|
51
|
+
interface FieldConfidence {
|
|
52
|
+
value_present: boolean;
|
|
53
|
+
type_match: boolean;
|
|
54
|
+
confidence: number;
|
|
55
|
+
source?: string;
|
|
56
|
+
}
|
|
57
|
+
interface SchemaQualityMetadata {
|
|
58
|
+
required_fields_total?: number;
|
|
59
|
+
required_fields_filled?: number;
|
|
60
|
+
missing_required_fields?: string[];
|
|
61
|
+
required_fields_guaranteed?: boolean;
|
|
62
|
+
required_coverage_pct?: number;
|
|
63
|
+
validation_errors?: SchemaValidationError[];
|
|
64
|
+
schema_adherence_score?: number;
|
|
65
|
+
field_confidence?: Record<string, FieldConfidence>;
|
|
66
|
+
}
|
|
67
|
+
interface ParseMetadata {
|
|
68
|
+
pdf?: Record<string, unknown>;
|
|
69
|
+
processing?: Record<string, unknown>;
|
|
70
|
+
structure?: Record<string, unknown>;
|
|
71
|
+
ocr?: Record<string, unknown>;
|
|
72
|
+
schema_quality?: SchemaQualityMetadata;
|
|
73
|
+
[key: string]: unknown;
|
|
74
|
+
}
|
|
27
75
|
interface StreamEvent {
|
|
28
76
|
event: string;
|
|
29
77
|
data: Record<string, unknown>;
|
|
@@ -173,6 +221,11 @@ declare class OxPDFClient {
|
|
|
173
221
|
upload(file: Blob | Buffer | Uint8Array, filename: string, options?: UploadOptions): Promise<UploadResult>;
|
|
174
222
|
/** Poll the status of an async PDF processing job. */
|
|
175
223
|
jobStatus(jobId: string): Promise<JobStatus>;
|
|
224
|
+
/**
|
|
225
|
+
* Wait until an async job reaches a terminal state.
|
|
226
|
+
* Throws on timeout.
|
|
227
|
+
*/
|
|
228
|
+
waitForJob(jobId: string, options?: WaitForJobOptions): Promise<JobStatus>;
|
|
176
229
|
/** Validate a PDF without full processing (dry-run). */
|
|
177
230
|
validate(file: Blob | Buffer | Uint8Array, filename: string, options?: ValidateOptions): Promise<Record<string, unknown>>;
|
|
178
231
|
/** Extract images from a PDF. */
|
|
@@ -229,4 +282,4 @@ declare class OxPDFError extends Error {
|
|
|
229
282
|
constructor(message: string, statusCode?: number, responseBody?: string);
|
|
230
283
|
}
|
|
231
284
|
|
|
232
|
-
export { type AnalyticsResult, type ClientOptions, type CreateSchemaOptions, type ExtractImagesOptions, type FileInfo, type FileListResult, type GenerateSchemaOptions, type GenerateSchemaResult, type ImageInfo, type ImageListResult, type ImageUrlResult, type JobStatus, OxPDFClient, OxPDFError, type ParseOptions, type ParseResult, type ParseStreamOptions, type SchemaInfo, type SchemaTemplate, type StreamEvent, type UpdateSchemaOptions, type UploadOptions, type UploadResult, type ValidateOptions };
|
|
285
|
+
export { type AnalyticsResult, type ClientOptions, type CreateSchemaOptions, type ExtractImagesOptions, type FileInfo, type FileListResult, type GenerateSchemaOptions, type GenerateSchemaResult, type ImageInfo, type ImageListResult, type ImageUrlResult, type JobStatus, OxPDFClient, OxPDFError, type ParseMetadata, type ParseOptions, type ParseResult, type ParseStreamOptions, type RetryOptions, type SchemaInfo, type SchemaQualityMetadata, type SchemaTemplate, type SchemaValidationError, type StreamEvent, type UpdateSchemaOptions, type UploadOptions, type UploadResult, type ValidateOptions, type WaitForJobOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,24 @@ interface ClientOptions {
|
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
/** Request timeout in milliseconds (default: 120_000) */
|
|
5
5
|
timeout?: number;
|
|
6
|
+
/** Retry settings for transient failures (network, 429, 5xx). */
|
|
7
|
+
retry?: RetryOptions;
|
|
8
|
+
}
|
|
9
|
+
interface RetryOptions {
|
|
10
|
+
/** Maximum retries per request (default: 2). */
|
|
11
|
+
maxRetries?: number;
|
|
12
|
+
/** Initial backoff delay in milliseconds (default: 500). */
|
|
13
|
+
initialDelayMs?: number;
|
|
14
|
+
/** Multiplier applied on each retry (default: 2). */
|
|
15
|
+
backoffMultiplier?: number;
|
|
16
|
+
/** HTTP statuses to retry (default: 429, 500, 502, 503, 504). */
|
|
17
|
+
retryableStatusCodes?: number[];
|
|
18
|
+
}
|
|
19
|
+
interface WaitForJobOptions {
|
|
20
|
+
/** Poll interval in milliseconds (default: 2000). */
|
|
21
|
+
intervalMs?: number;
|
|
22
|
+
/** Overall timeout in milliseconds (default: 120000). */
|
|
23
|
+
timeoutMs?: number;
|
|
6
24
|
}
|
|
7
25
|
interface ParseOptions {
|
|
8
26
|
schema?: Record<string, unknown>;
|
|
@@ -19,11 +37,41 @@ interface ParseResult {
|
|
|
19
37
|
success: boolean;
|
|
20
38
|
data?: Record<string, unknown>;
|
|
21
39
|
error?: string;
|
|
22
|
-
metadata?:
|
|
40
|
+
metadata?: ParseMetadata;
|
|
23
41
|
cached?: boolean;
|
|
24
42
|
quota?: Record<string, unknown>;
|
|
25
43
|
[key: string]: unknown;
|
|
26
44
|
}
|
|
45
|
+
interface SchemaValidationError {
|
|
46
|
+
path: string;
|
|
47
|
+
expected: string[];
|
|
48
|
+
actual: string;
|
|
49
|
+
message: string;
|
|
50
|
+
}
|
|
51
|
+
interface FieldConfidence {
|
|
52
|
+
value_present: boolean;
|
|
53
|
+
type_match: boolean;
|
|
54
|
+
confidence: number;
|
|
55
|
+
source?: string;
|
|
56
|
+
}
|
|
57
|
+
interface SchemaQualityMetadata {
|
|
58
|
+
required_fields_total?: number;
|
|
59
|
+
required_fields_filled?: number;
|
|
60
|
+
missing_required_fields?: string[];
|
|
61
|
+
required_fields_guaranteed?: boolean;
|
|
62
|
+
required_coverage_pct?: number;
|
|
63
|
+
validation_errors?: SchemaValidationError[];
|
|
64
|
+
schema_adherence_score?: number;
|
|
65
|
+
field_confidence?: Record<string, FieldConfidence>;
|
|
66
|
+
}
|
|
67
|
+
interface ParseMetadata {
|
|
68
|
+
pdf?: Record<string, unknown>;
|
|
69
|
+
processing?: Record<string, unknown>;
|
|
70
|
+
structure?: Record<string, unknown>;
|
|
71
|
+
ocr?: Record<string, unknown>;
|
|
72
|
+
schema_quality?: SchemaQualityMetadata;
|
|
73
|
+
[key: string]: unknown;
|
|
74
|
+
}
|
|
27
75
|
interface StreamEvent {
|
|
28
76
|
event: string;
|
|
29
77
|
data: Record<string, unknown>;
|
|
@@ -173,6 +221,11 @@ declare class OxPDFClient {
|
|
|
173
221
|
upload(file: Blob | Buffer | Uint8Array, filename: string, options?: UploadOptions): Promise<UploadResult>;
|
|
174
222
|
/** Poll the status of an async PDF processing job. */
|
|
175
223
|
jobStatus(jobId: string): Promise<JobStatus>;
|
|
224
|
+
/**
|
|
225
|
+
* Wait until an async job reaches a terminal state.
|
|
226
|
+
* Throws on timeout.
|
|
227
|
+
*/
|
|
228
|
+
waitForJob(jobId: string, options?: WaitForJobOptions): Promise<JobStatus>;
|
|
176
229
|
/** Validate a PDF without full processing (dry-run). */
|
|
177
230
|
validate(file: Blob | Buffer | Uint8Array, filename: string, options?: ValidateOptions): Promise<Record<string, unknown>>;
|
|
178
231
|
/** Extract images from a PDF. */
|
|
@@ -229,4 +282,4 @@ declare class OxPDFError extends Error {
|
|
|
229
282
|
constructor(message: string, statusCode?: number, responseBody?: string);
|
|
230
283
|
}
|
|
231
284
|
|
|
232
|
-
export { type AnalyticsResult, type ClientOptions, type CreateSchemaOptions, type ExtractImagesOptions, type FileInfo, type FileListResult, type GenerateSchemaOptions, type GenerateSchemaResult, type ImageInfo, type ImageListResult, type ImageUrlResult, type JobStatus, OxPDFClient, OxPDFError, type ParseOptions, type ParseResult, type ParseStreamOptions, type SchemaInfo, type SchemaTemplate, type StreamEvent, type UpdateSchemaOptions, type UploadOptions, type UploadResult, type ValidateOptions };
|
|
285
|
+
export { type AnalyticsResult, type ClientOptions, type CreateSchemaOptions, type ExtractImagesOptions, type FileInfo, type FileListResult, type GenerateSchemaOptions, type GenerateSchemaResult, type ImageInfo, type ImageListResult, type ImageUrlResult, type JobStatus, OxPDFClient, OxPDFError, type ParseMetadata, type ParseOptions, type ParseResult, type ParseStreamOptions, type RetryOptions, type SchemaInfo, type SchemaQualityMetadata, type SchemaTemplate, type SchemaValidationError, type StreamEvent, type UpdateSchemaOptions, type UploadOptions, type UploadResult, type ValidateOptions, type WaitForJobOptions };
|
package/dist/index.js
CHANGED
|
@@ -11,12 +11,21 @@ var OxPDFError = class extends Error {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
// src/client.ts
|
|
14
|
-
var DEFAULT_BASE_URL = "https://api.0xpdf.
|
|
14
|
+
var DEFAULT_BASE_URL = "https://api.0xpdf.io/api/v1";
|
|
15
15
|
var DEFAULT_TIMEOUT = 12e4;
|
|
16
|
+
var DEFAULT_RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];
|
|
17
|
+
var DEFAULT_RETRY = {
|
|
18
|
+
maxRetries: 2,
|
|
19
|
+
initialDelayMs: 500,
|
|
20
|
+
backoffMultiplier: 2,
|
|
21
|
+
retryableStatusCodes: DEFAULT_RETRYABLE_STATUS_CODES
|
|
22
|
+
};
|
|
23
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
24
|
var OxPDFClient = class {
|
|
17
25
|
#apiKey;
|
|
18
26
|
#baseUrl;
|
|
19
27
|
#timeout;
|
|
28
|
+
#retry;
|
|
20
29
|
constructor(options) {
|
|
21
30
|
if (!options.apiKey) {
|
|
22
31
|
throw new OxPDFError("apiKey is required");
|
|
@@ -24,6 +33,12 @@ var OxPDFClient = class {
|
|
|
24
33
|
this.#apiKey = options.apiKey;
|
|
25
34
|
this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
26
35
|
this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
36
|
+
this.#retry = {
|
|
37
|
+
maxRetries: options.retry?.maxRetries ?? DEFAULT_RETRY.maxRetries,
|
|
38
|
+
initialDelayMs: options.retry?.initialDelayMs ?? DEFAULT_RETRY.initialDelayMs,
|
|
39
|
+
backoffMultiplier: options.retry?.backoffMultiplier ?? DEFAULT_RETRY.backoffMultiplier,
|
|
40
|
+
retryableStatusCodes: options.retry?.retryableStatusCodes ?? DEFAULT_RETRY.retryableStatusCodes
|
|
41
|
+
};
|
|
27
42
|
}
|
|
28
43
|
// ── internal helpers ─────────────────────────────────────────────
|
|
29
44
|
#url(path) {
|
|
@@ -36,45 +51,59 @@ var OxPDFClient = class {
|
|
|
36
51
|
url.searchParams.set(k, v);
|
|
37
52
|
}
|
|
38
53
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
resp = await fetch(url.toString(), {
|
|
44
|
-
method,
|
|
45
|
-
headers: {
|
|
46
|
-
"X-API-Key": this.#apiKey,
|
|
47
|
-
...init?.headers
|
|
48
|
-
},
|
|
49
|
-
body: init?.body,
|
|
50
|
-
signal: controller.signal
|
|
51
|
-
});
|
|
52
|
-
} catch (err) {
|
|
53
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
54
|
-
throw new OxPDFError(`Request failed: ${msg}`);
|
|
55
|
-
} finally {
|
|
56
|
-
clearTimeout(timer);
|
|
57
|
-
}
|
|
58
|
-
if (resp.status === 204) return {};
|
|
59
|
-
if (!resp.ok) {
|
|
60
|
-
const text2 = await resp.text();
|
|
61
|
-
let detail;
|
|
54
|
+
for (let attempt = 0; attempt <= this.#retry.maxRetries; attempt++) {
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const timer = setTimeout(() => controller.abort(), this.#timeout);
|
|
57
|
+
let resp;
|
|
62
58
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
resp = await fetch(url.toString(), {
|
|
60
|
+
method,
|
|
61
|
+
headers: {
|
|
62
|
+
"X-API-Key": this.#apiKey,
|
|
63
|
+
...init?.headers
|
|
64
|
+
},
|
|
65
|
+
body: init?.body,
|
|
66
|
+
signal: controller.signal
|
|
67
|
+
});
|
|
68
|
+
} catch (err) {
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
if (attempt < this.#retry.maxRetries) {
|
|
71
|
+
const delay = this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);
|
|
72
|
+
await sleep(delay);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
76
|
+
throw new OxPDFError(`Request failed: ${msg}`);
|
|
77
|
+
} finally {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
}
|
|
80
|
+
if (resp.status === 204) return {};
|
|
81
|
+
if (!resp.ok) {
|
|
82
|
+
const text2 = await resp.text();
|
|
83
|
+
if (this.#retry.retryableStatusCodes.includes(resp.status) && attempt < this.#retry.maxRetries) {
|
|
84
|
+
const delay = this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);
|
|
85
|
+
await sleep(delay);
|
|
86
|
+
continue;
|
|
69
87
|
}
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
let detail;
|
|
89
|
+
try {
|
|
90
|
+
const body = JSON.parse(text2);
|
|
91
|
+
const raw = body.detail ?? body.error ?? text2;
|
|
92
|
+
if (Array.isArray(raw)) {
|
|
93
|
+
detail = raw.map((d) => d.msg ?? JSON.stringify(d)).join("; ");
|
|
94
|
+
} else {
|
|
95
|
+
detail = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
detail = text2 || resp.statusText || `HTTP ${resp.status}`;
|
|
99
|
+
}
|
|
100
|
+
throw new OxPDFError(detail, resp.status, text2);
|
|
72
101
|
}
|
|
73
|
-
|
|
102
|
+
const text = await resp.text();
|
|
103
|
+
if (!text) return {};
|
|
104
|
+
return JSON.parse(text);
|
|
74
105
|
}
|
|
75
|
-
|
|
76
|
-
if (!text) return {};
|
|
77
|
-
return JSON.parse(text);
|
|
106
|
+
throw new OxPDFError("Request failed after retries");
|
|
78
107
|
}
|
|
79
108
|
#buildPdfForm(file, filename, fields) {
|
|
80
109
|
if (!filename.toLowerCase().endsWith(".pdf")) {
|
|
@@ -218,6 +247,27 @@ var OxPDFClient = class {
|
|
|
218
247
|
async jobStatus(jobId) {
|
|
219
248
|
return this.#request("GET", `pdf/status/${jobId}`);
|
|
220
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Wait until an async job reaches a terminal state.
|
|
252
|
+
* Throws on timeout.
|
|
253
|
+
*/
|
|
254
|
+
async waitForJob(jobId, options = {}) {
|
|
255
|
+
const intervalMs = options.intervalMs ?? 2e3;
|
|
256
|
+
const timeoutMs = options.timeoutMs ?? 12e4;
|
|
257
|
+
const startedAt = Date.now();
|
|
258
|
+
while (true) {
|
|
259
|
+
const status = await this.jobStatus(jobId);
|
|
260
|
+
if (status.status === "completed" || status.status === "failed") {
|
|
261
|
+
return status;
|
|
262
|
+
}
|
|
263
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
264
|
+
throw new OxPDFError(
|
|
265
|
+
`Timed out waiting for job ${jobId} after ${timeoutMs}ms`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
await sleep(intervalMs);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
221
271
|
// ── PDF validation ───────────────────────────────────────────────
|
|
222
272
|
/** Validate a PDF without full processing (dry-run). */
|
|
223
273
|
async validate(file, filename, options = {}) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["export class OxPDFError extends Error {\n readonly statusCode: number | undefined;\n readonly responseBody: string | undefined;\n\n constructor(\n message: string,\n statusCode?: number,\n responseBody?: string,\n ) {\n super(message);\n this.name = \"OxPDFError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n }\n}\n","import { OxPDFError } from \"./errors.js\";\nimport type {\n AnalyticsResult,\n ClientOptions,\n CreateSchemaOptions,\n ExtractImagesOptions,\n FileInfo,\n FileListResult,\n GenerateSchemaOptions,\n GenerateSchemaResult,\n ImageListResult,\n ImageUrlResult,\n JobStatus,\n ParseOptions,\n ParseResult,\n ParseStreamOptions,\n SchemaInfo,\n SchemaTemplate,\n StreamEvent,\n UpdateSchemaOptions,\n UploadOptions,\n UploadResult,\n ValidateOptions,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.0xpdf.com/api/v1\";\nconst DEFAULT_TIMEOUT = 120_000;\n\nexport class OxPDFClient {\n readonly #apiKey: string;\n readonly #baseUrl: string;\n readonly #timeout: number;\n\n constructor(options: ClientOptions) {\n if (!options.apiKey) {\n throw new OxPDFError(\"apiKey is required\");\n }\n this.#apiKey = options.apiKey;\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;\n }\n\n // ── internal helpers ─────────────────────────────────────────────\n\n #url(path: string): string {\n return `${this.#baseUrl}/${path.replace(/^\\/+/, \"\")}`;\n }\n\n async #request<T = Record<string, unknown>>(\n method: string,\n path: string,\n init?: {\n params?: Record<string, string>;\n body?: FormData | string;\n headers?: Record<string, string>;\n },\n ): Promise<T> {\n const url = new URL(this.#url(path));\n if (init?.params) {\n for (const [k, v] of Object.entries(init.params)) {\n url.searchParams.set(k, v);\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.#timeout);\n\n let resp: Response;\n try {\n resp = await fetch(url.toString(), {\n method,\n headers: {\n \"X-API-Key\": this.#apiKey,\n ...init?.headers,\n },\n body: init?.body,\n signal: controller.signal,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Request failed: ${msg}`);\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 204) return {} as T;\n\n if (!resp.ok) {\n const text = await resp.text();\n let detail: string;\n try {\n const body = JSON.parse(text);\n const raw = body.detail ?? body.error ?? text;\n if (Array.isArray(raw)) {\n detail = raw.map((d: Record<string, unknown>) => d.msg ?? JSON.stringify(d)).join(\"; \");\n } else {\n detail = typeof raw === \"string\" ? raw : JSON.stringify(raw);\n }\n } catch {\n detail = text || resp.statusText || `HTTP ${resp.status}`;\n }\n throw new OxPDFError(detail, resp.status, text);\n }\n\n const text = await resp.text();\n if (!text) return {} as T;\n return JSON.parse(text) as T;\n }\n\n #buildPdfForm(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n fields?: Record<string, string>,\n ): FormData {\n if (!filename.toLowerCase().endsWith(\".pdf\")) {\n throw new OxPDFError(\"File must be a PDF\");\n }\n\n const form = new FormData();\n let blob: Blob;\n if (file instanceof Blob) {\n blob = file;\n } else {\n const arr = new Uint8Array(file.buffer, file.byteOffset, file.byteLength);\n blob = new Blob([arr as unknown as Uint8Array<ArrayBuffer>], {\n type: \"application/pdf\",\n });\n }\n form.append(\"file\", blob, filename);\n if (fields) {\n for (const [k, v] of Object.entries(fields)) form.append(k, v);\n }\n return form;\n }\n\n // ── PDF parsing ──────────────────────────────────────────────────\n\n /** Parse a PDF and return structured JSON. */\n async parse(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseOptions = {},\n ): Promise<ParseResult> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {};\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n return this.#request<ParseResult>(\"POST\", \"pdf/parse\", {\n params: Object.keys(params).length ? params : undefined,\n body: form,\n });\n }\n\n /** Parse a PDF from a file path (Node.js only). */\n async parseFile(filePath: string, options: ParseOptions = {}): Promise<ParseResult> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n return this.parse(buf, basename(filePath), options);\n }\n\n /**\n * Streaming parse via Server-Sent Events.\n * Returns an async generator that yields ``StreamEvent`` objects.\n */\n async *parseStream(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {\n batch_size: String(options.batchSize ?? 5),\n };\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n const url = new URL(this.#url(\"pdf/parse-stream\"));\n for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 300_000);\n\n let resp: Response;\n try {\n resp = await fetch(url.toString(), {\n method: \"POST\",\n headers: { \"X-API-Key\": this.#apiKey },\n body: form,\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Stream request failed: ${msg}`);\n }\n\n if (!resp.ok) {\n clearTimeout(timer);\n const text = await resp.text();\n throw new OxPDFError(text, resp.status, text);\n }\n\n try {\n const reader = resp.body?.getReader();\n if (!reader) throw new OxPDFError(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventType = \"message\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const raw = line.slice(5).trim();\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(raw);\n } catch {\n data = { raw };\n }\n yield { event: eventType, data };\n eventType = \"message\";\n }\n }\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n /** Streaming parse from a file path (Node.js only). */\n async *parseFileStream(\n filePath: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n yield* this.parseStream(buf, basename(filePath), options);\n }\n\n // ── Async upload (job queue) ─────────────────────────────────────\n\n /** Upload a PDF for async background processing. Returns a job_id. */\n async upload(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: UploadOptions = {},\n ): Promise<UploadResult> {\n const params: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n\n return this.#request<UploadResult>(\"POST\", \"pdf/upload\", {\n params,\n body: form,\n });\n }\n\n /** Poll the status of an async PDF processing job. */\n async jobStatus(jobId: string): Promise<JobStatus> {\n return this.#request<JobStatus>(\"GET\", `pdf/status/${jobId}`);\n }\n\n // ── PDF validation ───────────────────────────────────────────────\n\n /** Validate a PDF without full processing (dry-run). */\n async validate(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ValidateOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = { dry_run: \"true\" };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/validate\", { params, body: form });\n }\n\n // ── Image extraction ─────────────────────────────────────────────\n\n /** Extract images from a PDF. */\n async extractImages(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ExtractImagesOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = {\n min_width: String(options.minWidth ?? 50),\n min_height: String(options.minHeight ?? 50),\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/parse-images\", { params, body: form });\n }\n\n // ── Image management ─────────────────────────────────────────────\n\n /** List extracted images. */\n async listImages(limit = 100, offset = 0): Promise<ImageListResult> {\n return this.#request<ImageListResult>(\"GET\", \"pdf/images\", {\n params: { limit: String(limit), offset: String(offset) },\n });\n }\n\n /** Get or refresh a presigned URL for an image. */\n async getImageUrl(imageId: string, expirationSeconds = 3600): Promise<ImageUrlResult> {\n return this.#request<ImageUrlResult>(\"GET\", `pdf/images/${imageId}/url`, {\n params: { expiration_seconds: String(expirationSeconds) },\n });\n }\n\n /** Delete a specific image. */\n async deleteImage(imageId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/images/${imageId}`);\n }\n\n /** Delete all extracted images. */\n async deleteAllImages(): Promise<Record<string, unknown>> {\n return this.#request(\"DELETE\", \"pdf/images\");\n }\n\n // ── File management ──────────────────────────────────────────────\n\n /** List previously uploaded PDFs. */\n async listFiles(): Promise<FileListResult> {\n return this.#request<FileListResult>(\"GET\", \"pdf/files\");\n }\n\n /** Get metadata and download URL for an uploaded PDF. */\n async getFile(pdfId: string): Promise<FileInfo> {\n return this.#request<FileInfo>(\"GET\", `pdf/files/${pdfId}`);\n }\n\n /** Delete an uploaded PDF. */\n async deleteFile(pdfId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/files/${pdfId}`);\n }\n\n // ── Schema templates ─────────────────────────────────────────────\n\n /** List pre-built schema templates (pdf route). */\n async listTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\"GET\", \"pdf/templates\");\n return res.templates ?? [];\n }\n\n /** List schema templates from /schemas/templates/list. */\n async listSchemaTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\n \"GET\",\n \"schemas/templates/list\",\n );\n return res.templates ?? [];\n }\n\n /** Get a specific schema template with full definition. */\n async getSchemaTemplate(templateId: string): Promise<SchemaTemplate> {\n return this.#request<SchemaTemplate>(\"GET\", `schemas/templates/${templateId}`);\n }\n\n // ── Schema CRUD ──────────────────────────────────────────────────\n\n /** List user's saved schemas. */\n async listSchemas(): Promise<SchemaInfo[]> {\n const res = await this.#request<{ schemas: SchemaInfo[] }>(\"GET\", \"schemas\");\n return res.schemas ?? [];\n }\n\n /** Get a specific schema by ID. */\n async getSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"GET\", `schemas/${schemaId}`);\n }\n\n /** Create a new JSON schema. */\n async createSchema(options: CreateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"POST\", \"schemas\", {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Update an existing schema. */\n async updateSchema(schemaId: string, options: UpdateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PUT\", `schemas/${schemaId}`, {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Delete a schema. */\n async deleteSchema(schemaId: string): Promise<void> {\n await this.#request(\"DELETE\", `schemas/${schemaId}`);\n }\n\n /** Set a schema as the default. */\n async setDefaultSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PATCH\", `schemas/${schemaId}/set-default`);\n }\n\n /** Generate a schema using AI from a natural-language description. */\n async generateSchema(options: GenerateSchemaOptions): Promise<GenerateSchemaResult> {\n const body: Record<string, unknown> = { description: options.description };\n if (options.refinement) body.refinement = options.refinement;\n if (options.currentSchema) body.current_schema = options.currentSchema;\n if (options.selectedText) body.selected_text = options.selectedText;\n\n return this.#request<GenerateSchemaResult>(\"POST\", \"schemas/generate\", {\n body: JSON.stringify(body),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Analytics ────────────────────────────────────────────────────\n\n /** Get usage analytics for the current user/org. */\n async getAnalytics(): Promise<AnalyticsResult> {\n return this.#request<AnalyticsResult>(\"GET\", \"analytics/user\");\n }\n\n /** Submit in-app feedback. */\n async submitFeedback(feedback: string): Promise<{ success: boolean }> {\n return this.#request<{ success: boolean }>(\"POST\", \"analytics/feedback\", {\n body: JSON.stringify({ feedback }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Pricing ──────────────────────────────────────────────────────\n\n /** Get available pricing tiers. */\n async getPricing(billingCycle = \"monthly\"): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing\", {\n params: { billing_cycle: billingCycle },\n });\n }\n\n /** Get the current user's tier and quota. */\n async getCurrentTier(): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing/current\");\n }\n}\n"],"mappings":"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","names":["text"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["export class OxPDFError extends Error {\n readonly statusCode: number | undefined;\n readonly responseBody: string | undefined;\n\n constructor(\n message: string,\n statusCode?: number,\n responseBody?: string,\n ) {\n super(message);\n this.name = \"OxPDFError\";\n this.statusCode = statusCode;\n this.responseBody = responseBody;\n }\n}\n","import { OxPDFError } from \"./errors.js\";\nimport type {\n AnalyticsResult,\n ClientOptions,\n CreateSchemaOptions,\n ExtractImagesOptions,\n FileInfo,\n FileListResult,\n GenerateSchemaOptions,\n GenerateSchemaResult,\n ImageListResult,\n ImageUrlResult,\n JobStatus,\n ParseOptions,\n ParseResult,\n ParseStreamOptions,\n RetryOptions,\n SchemaInfo,\n SchemaTemplate,\n StreamEvent,\n UpdateSchemaOptions,\n UploadOptions,\n UploadResult,\n ValidateOptions,\n WaitForJobOptions,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.0xpdf.io/api/v1\";\nconst DEFAULT_TIMEOUT = 120_000;\nconst DEFAULT_RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];\nconst DEFAULT_RETRY: Required<RetryOptions> = {\n maxRetries: 2,\n initialDelayMs: 500,\n backoffMultiplier: 2,\n retryableStatusCodes: DEFAULT_RETRYABLE_STATUS_CODES,\n};\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport class OxPDFClient {\n readonly #apiKey: string;\n readonly #baseUrl: string;\n readonly #timeout: number;\n readonly #retry: Required<RetryOptions>;\n\n constructor(options: ClientOptions) {\n if (!options.apiKey) {\n throw new OxPDFError(\"apiKey is required\");\n }\n this.#apiKey = options.apiKey;\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;\n this.#retry = {\n maxRetries: options.retry?.maxRetries ?? DEFAULT_RETRY.maxRetries,\n initialDelayMs: options.retry?.initialDelayMs ?? DEFAULT_RETRY.initialDelayMs,\n backoffMultiplier: options.retry?.backoffMultiplier ?? DEFAULT_RETRY.backoffMultiplier,\n retryableStatusCodes:\n options.retry?.retryableStatusCodes ?? DEFAULT_RETRY.retryableStatusCodes,\n };\n }\n\n // ── internal helpers ─────────────────────────────────────────────\n\n #url(path: string): string {\n return `${this.#baseUrl}/${path.replace(/^\\/+/, \"\")}`;\n }\n\n async #request<T = Record<string, unknown>>(\n method: string,\n path: string,\n init?: {\n params?: Record<string, string>;\n body?: FormData | string;\n headers?: Record<string, string>;\n },\n ): Promise<T> {\n const url = new URL(this.#url(path));\n if (init?.params) {\n for (const [k, v] of Object.entries(init.params)) {\n url.searchParams.set(k, v);\n }\n }\n\n for (let attempt = 0; attempt <= this.#retry.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.#timeout);\n let resp: Response;\n\n try {\n resp = await fetch(url.toString(), {\n method,\n headers: {\n \"X-API-Key\": this.#apiKey,\n ...init?.headers,\n },\n body: init?.body,\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n if (attempt < this.#retry.maxRetries) {\n const delay =\n this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);\n await sleep(delay);\n continue;\n }\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Request failed: ${msg}`);\n } finally {\n clearTimeout(timer);\n }\n\n if (resp.status === 204) return {} as T;\n\n if (!resp.ok) {\n const text = await resp.text();\n if (\n this.#retry.retryableStatusCodes.includes(resp.status) &&\n attempt < this.#retry.maxRetries\n ) {\n const delay =\n this.#retry.initialDelayMs * Math.pow(this.#retry.backoffMultiplier, attempt);\n await sleep(delay);\n continue;\n }\n\n let detail: string;\n try {\n const body = JSON.parse(text);\n const raw = body.detail ?? body.error ?? text;\n if (Array.isArray(raw)) {\n detail = raw.map((d: Record<string, unknown>) => d.msg ?? JSON.stringify(d)).join(\"; \");\n } else {\n detail = typeof raw === \"string\" ? raw : JSON.stringify(raw);\n }\n } catch {\n detail = text || resp.statusText || `HTTP ${resp.status}`;\n }\n throw new OxPDFError(detail, resp.status, text);\n }\n\n const text = await resp.text();\n if (!text) return {} as T;\n return JSON.parse(text) as T;\n }\n\n throw new OxPDFError(\"Request failed after retries\");\n }\n\n #buildPdfForm(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n fields?: Record<string, string>,\n ): FormData {\n if (!filename.toLowerCase().endsWith(\".pdf\")) {\n throw new OxPDFError(\"File must be a PDF\");\n }\n\n const form = new FormData();\n let blob: Blob;\n if (file instanceof Blob) {\n blob = file;\n } else {\n const arr = new Uint8Array(file.buffer, file.byteOffset, file.byteLength);\n blob = new Blob([arr as unknown as Uint8Array<ArrayBuffer>], {\n type: \"application/pdf\",\n });\n }\n form.append(\"file\", blob, filename);\n if (fields) {\n for (const [k, v] of Object.entries(fields)) form.append(k, v);\n }\n return form;\n }\n\n // ── PDF parsing ──────────────────────────────────────────────────\n\n /** Parse a PDF and return structured JSON. */\n async parse(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseOptions = {},\n ): Promise<ParseResult> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {};\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n return this.#request<ParseResult>(\"POST\", \"pdf/parse\", {\n params: Object.keys(params).length ? params : undefined,\n body: form,\n });\n }\n\n /** Parse a PDF from a file path (Node.js only). */\n async parseFile(filePath: string, options: ParseOptions = {}): Promise<ParseResult> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n return this.parse(buf, basename(filePath), options);\n }\n\n /**\n * Streaming parse via Server-Sent Events.\n * Returns an async generator that yields ``StreamEvent`` objects.\n */\n async *parseStream(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const formFields: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n };\n if (options.ocrEngine) formFields.ocr_engine = options.ocrEngine;\n if (options.schema) formFields.schema_json = JSON.stringify(options.schema);\n\n const params: Record<string, string> = {\n batch_size: String(options.batchSize ?? 5),\n };\n if (options.schemaTemplate) params.schema_template = options.schemaTemplate;\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename, formFields);\n\n const url = new URL(this.#url(\"pdf/parse-stream\"));\n for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 300_000);\n\n let resp: Response;\n try {\n resp = await fetch(url.toString(), {\n method: \"POST\",\n headers: { \"X-API-Key\": this.#apiKey },\n body: form,\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n const msg = err instanceof Error ? err.message : String(err);\n throw new OxPDFError(`Stream request failed: ${msg}`);\n }\n\n if (!resp.ok) {\n clearTimeout(timer);\n const text = await resp.text();\n throw new OxPDFError(text, resp.status, text);\n }\n\n try {\n const reader = resp.body?.getReader();\n if (!reader) throw new OxPDFError(\"No response body\");\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventType = \"message\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n const raw = line.slice(5).trim();\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(raw);\n } catch {\n data = { raw };\n }\n yield { event: eventType, data };\n eventType = \"message\";\n }\n }\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n /** Streaming parse from a file path (Node.js only). */\n async *parseFileStream(\n filePath: string,\n options: ParseStreamOptions = {},\n ): AsyncGenerator<StreamEvent> {\n const { readFile } = await import(\"node:fs/promises\");\n const { basename } = await import(\"node:path\");\n const buf = await readFile(filePath);\n yield* this.parseStream(buf, basename(filePath), options);\n }\n\n // ── Async upload (job queue) ─────────────────────────────────────\n\n /** Upload a PDF for async background processing. Returns a job_id. */\n async upload(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: UploadOptions = {},\n ): Promise<UploadResult> {\n const params: Record<string, string> = {\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n\n return this.#request<UploadResult>(\"POST\", \"pdf/upload\", {\n params,\n body: form,\n });\n }\n\n /** Poll the status of an async PDF processing job. */\n async jobStatus(jobId: string): Promise<JobStatus> {\n return this.#request<JobStatus>(\"GET\", `pdf/status/${jobId}`);\n }\n\n /**\n * Wait until an async job reaches a terminal state.\n * Throws on timeout.\n */\n async waitForJob(jobId: string, options: WaitForJobOptions = {}): Promise<JobStatus> {\n const intervalMs = options.intervalMs ?? 2_000;\n const timeoutMs = options.timeoutMs ?? 120_000;\n const startedAt = Date.now();\n\n while (true) {\n const status = await this.jobStatus(jobId);\n if (status.status === \"completed\" || status.status === \"failed\") {\n return status;\n }\n if (Date.now() - startedAt > timeoutMs) {\n throw new OxPDFError(\n `Timed out waiting for job ${jobId} after ${timeoutMs}ms`,\n );\n }\n await sleep(intervalMs);\n }\n }\n\n // ── PDF validation ───────────────────────────────────────────────\n\n /** Validate a PDF without full processing (dry-run). */\n async validate(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ValidateOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = { dry_run: \"true\" };\n if (options.schemaId) params.schema_id = options.schemaId;\n if (options.schemaName) params.schema_name = options.schemaName;\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/validate\", { params, body: form });\n }\n\n // ── Image extraction ─────────────────────────────────────────────\n\n /** Extract images from a PDF. */\n async extractImages(\n file: Blob | Buffer | Uint8Array,\n filename: string,\n options: ExtractImagesOptions = {},\n ): Promise<Record<string, unknown>> {\n const params: Record<string, string> = {\n min_width: String(options.minWidth ?? 50),\n min_height: String(options.minHeight ?? 50),\n use_ocr: String(options.useOcr ?? false),\n ocr_engine: options.ocrEngine ?? \"surya\",\n };\n if (options.pages) params.pages = options.pages.join(\",\");\n\n const form = this.#buildPdfForm(file, filename);\n return this.#request(\"POST\", \"pdf/parse-images\", { params, body: form });\n }\n\n // ── Image management ─────────────────────────────────────────────\n\n /** List extracted images. */\n async listImages(limit = 100, offset = 0): Promise<ImageListResult> {\n return this.#request<ImageListResult>(\"GET\", \"pdf/images\", {\n params: { limit: String(limit), offset: String(offset) },\n });\n }\n\n /** Get or refresh a presigned URL for an image. */\n async getImageUrl(imageId: string, expirationSeconds = 3600): Promise<ImageUrlResult> {\n return this.#request<ImageUrlResult>(\"GET\", `pdf/images/${imageId}/url`, {\n params: { expiration_seconds: String(expirationSeconds) },\n });\n }\n\n /** Delete a specific image. */\n async deleteImage(imageId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/images/${imageId}`);\n }\n\n /** Delete all extracted images. */\n async deleteAllImages(): Promise<Record<string, unknown>> {\n return this.#request(\"DELETE\", \"pdf/images\");\n }\n\n // ── File management ──────────────────────────────────────────────\n\n /** List previously uploaded PDFs. */\n async listFiles(): Promise<FileListResult> {\n return this.#request<FileListResult>(\"GET\", \"pdf/files\");\n }\n\n /** Get metadata and download URL for an uploaded PDF. */\n async getFile(pdfId: string): Promise<FileInfo> {\n return this.#request<FileInfo>(\"GET\", `pdf/files/${pdfId}`);\n }\n\n /** Delete an uploaded PDF. */\n async deleteFile(pdfId: string): Promise<void> {\n await this.#request(\"DELETE\", `pdf/files/${pdfId}`);\n }\n\n // ── Schema templates ─────────────────────────────────────────────\n\n /** List pre-built schema templates (pdf route). */\n async listTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\"GET\", \"pdf/templates\");\n return res.templates ?? [];\n }\n\n /** List schema templates from /schemas/templates/list. */\n async listSchemaTemplates(): Promise<SchemaTemplate[]> {\n const res = await this.#request<{ templates: SchemaTemplate[] }>(\n \"GET\",\n \"schemas/templates/list\",\n );\n return res.templates ?? [];\n }\n\n /** Get a specific schema template with full definition. */\n async getSchemaTemplate(templateId: string): Promise<SchemaTemplate> {\n return this.#request<SchemaTemplate>(\"GET\", `schemas/templates/${templateId}`);\n }\n\n // ── Schema CRUD ──────────────────────────────────────────────────\n\n /** List user's saved schemas. */\n async listSchemas(): Promise<SchemaInfo[]> {\n const res = await this.#request<{ schemas: SchemaInfo[] }>(\"GET\", \"schemas\");\n return res.schemas ?? [];\n }\n\n /** Get a specific schema by ID. */\n async getSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"GET\", `schemas/${schemaId}`);\n }\n\n /** Create a new JSON schema. */\n async createSchema(options: CreateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"POST\", \"schemas\", {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Update an existing schema. */\n async updateSchema(schemaId: string, options: UpdateSchemaOptions): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PUT\", `schemas/${schemaId}`, {\n body: JSON.stringify({\n name: options.name,\n schema: options.schema,\n is_default: options.isDefault ?? false,\n }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n /** Delete a schema. */\n async deleteSchema(schemaId: string): Promise<void> {\n await this.#request(\"DELETE\", `schemas/${schemaId}`);\n }\n\n /** Set a schema as the default. */\n async setDefaultSchema(schemaId: string): Promise<SchemaInfo> {\n return this.#request<SchemaInfo>(\"PATCH\", `schemas/${schemaId}/set-default`);\n }\n\n /** Generate a schema using AI from a natural-language description. */\n async generateSchema(options: GenerateSchemaOptions): Promise<GenerateSchemaResult> {\n const body: Record<string, unknown> = { description: options.description };\n if (options.refinement) body.refinement = options.refinement;\n if (options.currentSchema) body.current_schema = options.currentSchema;\n if (options.selectedText) body.selected_text = options.selectedText;\n\n return this.#request<GenerateSchemaResult>(\"POST\", \"schemas/generate\", {\n body: JSON.stringify(body),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Analytics ────────────────────────────────────────────────────\n\n /** Get usage analytics for the current user/org. */\n async getAnalytics(): Promise<AnalyticsResult> {\n return this.#request<AnalyticsResult>(\"GET\", \"analytics/user\");\n }\n\n /** Submit in-app feedback. */\n async submitFeedback(feedback: string): Promise<{ success: boolean }> {\n return this.#request<{ success: boolean }>(\"POST\", \"analytics/feedback\", {\n body: JSON.stringify({ feedback }),\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n // ── Pricing ──────────────────────────────────────────────────────\n\n /** Get available pricing tiers. */\n async getPricing(billingCycle = \"monthly\"): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing\", {\n params: { billing_cycle: billingCycle },\n });\n }\n\n /** Get the current user's tier and quota. */\n async getCurrentTier(): Promise<Record<string, unknown>> {\n return this.#request(\"GET\", \"pricing/current\");\n }\n}\n"],"mappings":"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","names":["text"]}
|