@docmana/sdk 0.3.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +115 -247
  2. package/dist/api/execution-result.d.ts +3 -0
  3. package/dist/api/execution-status.d.ts +6 -0
  4. package/dist/api/run-flow.d.ts +6 -0
  5. package/dist/cli.mjs +217 -257
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/client.d.ts +21 -0
  8. package/dist/config.d.ts +21 -0
  9. package/dist/errors.d.ts +55 -0
  10. package/dist/files/resolve-input.d.ts +11 -0
  11. package/dist/http/http-client.d.ts +26 -0
  12. package/dist/index.d.ts +4 -349
  13. package/dist/index.js +159 -298
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +159 -298
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/models/docmana-api-document-execution-result.model.d.ts +9 -0
  18. package/dist/models/docmana-api-document-request.model.d.ts +15 -0
  19. package/dist/models/docmana-api-execution-result.model.d.ts +24 -0
  20. package/dist/models/docmana-api-node-result.model.d.ts +28 -0
  21. package/dist/models/docmana-classification-result.model.d.ts +3 -0
  22. package/dist/models/docmana-conclusion-result.model.d.ts +3 -0
  23. package/dist/models/docmana-cross-validation-result.model.d.ts +3 -0
  24. package/dist/models/docmana-document-mapping.model.d.ts +4 -0
  25. package/dist/models/docmana-document-result.model.d.ts +11 -0
  26. package/dist/models/docmana-execution-result.model.d.ts +15 -0
  27. package/dist/models/docmana-extraction-result.model.d.ts +3 -0
  28. package/dist/models/docmana-metadata-extraction-result.model.d.ts +3 -0
  29. package/dist/models/docmana-node-result.model.d.ts +7 -0
  30. package/dist/models/docmana-score-node-result.model.d.ts +5 -0
  31. package/dist/models/docmana-validation-result.model.d.ts +3 -0
  32. package/dist/models/document-content.model.d.ts +4 -0
  33. package/dist/models/execution-progress.model.d.ts +4 -0
  34. package/dist/models/execution-status.enum.d.ts +1 -0
  35. package/dist/models/flow-configs.model.d.ts +16 -0
  36. package/dist/models/flow-edge.model.d.ts +4 -0
  37. package/dist/models/flow-node-type.enum.d.ts +1 -0
  38. package/dist/models/flow-node.model.d.ts +33 -0
  39. package/dist/models/flow.model.d.ts +11 -0
  40. package/dist/models/index.d.ts +26 -0
  41. package/dist/models/node-translation-result.model.d.ts +7 -0
  42. package/dist/models/physical-document.model.d.ts +9 -0
  43. package/dist/models/virtual-document.model.d.ts +10 -0
  44. package/dist/polling/poll.d.ts +15 -0
  45. package/dist/types.d.ts +76 -0
  46. package/package.json +17 -14
  47. package/dist/index.d.cts +0 -349
package/dist/index.mjs CHANGED
@@ -1,28 +1,32 @@
1
1
  // src/config.ts
2
2
  var DEFAULTS = {
3
- apiBaseUrl: "https://api.docmana.ai",
4
3
  tokenEndpoint: "https://4fe70f5b-e013-4f65-9fa7-3109a33beba5.ciamlogin.com/4fe70f5b-e013-4f65-9fa7-3109a33beba5/oauth2/v2.0/token",
5
4
  scope: "api://d781e6ba-cc08-4618-8099-ad968abd2b9e/.default",
6
5
  timeoutMs: 3e5,
7
- pollIntervalMs: 2e3
6
+ pollIntervalMs: 2e3,
7
+ pollMaxIntervalMs: 1e4
8
8
  };
9
9
  function resolveConfig(config) {
10
- if (!config.clientId) throw new Error("DocmanaConfig.clientId is required");
11
- if (!config.clientSecret) throw new Error("DocmanaConfig.clientSecret is required");
12
- const apiBaseUrl = (config.apiBaseUrl ?? DEFAULTS.apiBaseUrl).replace(/\/+$/, "");
10
+ if (!config.apiBaseUrl) throw new Error("DocmanaConfig.apiBaseUrl is required");
11
+ if (!config.accessToken && !config.getAccessToken) {
12
+ throw new Error("DocmanaConfig.accessToken or DocmanaConfig.getAccessToken is required");
13
+ }
14
+ const apiBaseUrl = normalizeApiBaseUrl(config.apiBaseUrl);
13
15
  return {
14
- clientId: config.clientId,
15
- clientSecret: config.clientSecret,
16
16
  apiBaseUrl,
17
- tokenEndpoint: config.tokenEndpoint ?? DEFAULTS.tokenEndpoint,
18
- scope: config.scope ?? DEFAULTS.scope,
17
+ accessToken: config.accessToken,
18
+ getAccessToken: config.getAccessToken,
19
19
  timeoutMs: config.timeoutMs ?? DEFAULTS.timeoutMs,
20
20
  pollIntervalMs: config.pollIntervalMs ?? DEFAULTS.pollIntervalMs,
21
+ pollMaxIntervalMs: config.pollMaxIntervalMs ?? DEFAULTS.pollMaxIntervalMs,
21
22
  fetchImpl: config.fetch ?? fetch,
22
- headers: config.headers ?? {},
23
- tokenCache: config.tokenCache
23
+ headers: config.headers ?? {}
24
24
  };
25
25
  }
26
+ function normalizeApiBaseUrl(value) {
27
+ const trimmed = value.replace(/\/+$/, "");
28
+ return /\/v\d+$/i.test(trimmed) ? trimmed : `${trimmed}/v1`;
29
+ }
26
30
 
27
31
  // src/errors.ts
28
32
  var DocmanaError = class extends Error {
@@ -77,7 +81,14 @@ var DocmanaAbortError = class extends DocmanaError {
77
81
  super(message, { code: "aborted" });
78
82
  }
79
83
  };
80
- function errorFromResponse(status, message, requestId) {
84
+ var DocmanaRateLimitError = class extends DocmanaError {
85
+ retryAfterMs;
86
+ constructor(message, opts = {}) {
87
+ super(message, { ...opts, code: "rate_limited" });
88
+ this.retryAfterMs = opts.retryAfterMs;
89
+ }
90
+ };
91
+ function errorFromResponse(status, message, requestId, retryAfterMs) {
81
92
  const opts = { status, requestId };
82
93
  switch (status) {
83
94
  case 400:
@@ -88,91 +99,13 @@ function errorFromResponse(status, message, requestId) {
88
99
  return new DocmanaPermissionError(message, opts);
89
100
  case 404:
90
101
  return new DocmanaNotFoundError(message, opts);
102
+ case 429:
103
+ return new DocmanaRateLimitError(message, { ...opts, retryAfterMs });
91
104
  default:
92
105
  return new DocmanaError(message, opts);
93
106
  }
94
107
  }
95
108
 
96
- // src/auth/token-manager.ts
97
- var SAFETY_MARGIN_MS = 6e4;
98
- var TokenManager = class {
99
- constructor(opts) {
100
- this.opts = opts;
101
- }
102
- opts;
103
- token = null;
104
- expiresAt = 0;
105
- inflight = null;
106
- invalidate() {
107
- this.token = null;
108
- this.expiresAt = 0;
109
- void this.opts.tokenCache?.clear().catch(() => void 0);
110
- }
111
- async getToken() {
112
- if (this.token && Date.now() < this.expiresAt) return this.token;
113
- const cached = await this.readCachedToken();
114
- if (cached) return cached;
115
- if (this.inflight) return this.inflight;
116
- this.inflight = this.acquire().finally(() => {
117
- this.inflight = null;
118
- });
119
- return this.inflight;
120
- }
121
- async acquire() {
122
- const body = new URLSearchParams({
123
- grant_type: "client_credentials",
124
- client_id: this.opts.clientId,
125
- client_secret: this.opts.clientSecret,
126
- scope: this.opts.scope
127
- });
128
- const res = await this.opts.fetchImpl(this.opts.tokenEndpoint, {
129
- method: "POST",
130
- headers: { "content-type": "application/x-www-form-urlencoded" },
131
- body: body.toString()
132
- });
133
- if (!res.ok) {
134
- throw new DocmanaAuthError("Failed to acquire Docmana access token", { status: res.status });
135
- }
136
- const json = await res.json();
137
- if (typeof json.access_token !== "string" || json.access_token.length === 0 || typeof json.expires_in !== "number" || !Number.isFinite(json.expires_in)) {
138
- throw new DocmanaAuthError("Malformed token response from Docmana CIAM", {
139
- status: res.status
140
- });
141
- }
142
- this.token = json.access_token;
143
- this.expiresAt = Date.now() + json.expires_in * 1e3 - SAFETY_MARGIN_MS;
144
- await this.writeCachedToken().catch(() => void 0);
145
- return this.token;
146
- }
147
- async readCachedToken() {
148
- if (!this.opts.tokenCache) return null;
149
- let entry;
150
- try {
151
- entry = await this.opts.tokenCache.read();
152
- } catch {
153
- return null;
154
- }
155
- if (!entry) return null;
156
- if (entry.clientId !== this.opts.clientId || entry.tokenEndpoint !== this.opts.tokenEndpoint || entry.scope !== this.opts.scope || Date.now() >= entry.expiresAt) {
157
- await this.opts.tokenCache.clear().catch(() => void 0);
158
- return null;
159
- }
160
- this.token = entry.accessToken;
161
- this.expiresAt = entry.expiresAt;
162
- return this.token;
163
- }
164
- async writeCachedToken() {
165
- if (!this.opts.tokenCache || !this.token) return;
166
- await this.opts.tokenCache.write({
167
- accessToken: this.token,
168
- expiresAt: this.expiresAt,
169
- clientId: this.opts.clientId,
170
- tokenEndpoint: this.opts.tokenEndpoint,
171
- scope: this.opts.scope
172
- });
173
- }
174
- };
175
-
176
109
  // src/http/http-client.ts
177
110
  var HttpClient = class {
178
111
  constructor(opts) {
@@ -191,19 +124,23 @@ var HttpClient = class {
191
124
  }
192
125
  async requestRaw(method, path, options = {}) {
193
126
  let res = await this.send(method, path, options);
194
- if (res.status === 401) {
195
- this.opts.tokenManager.invalidate();
196
- res = await this.send(method, path, options);
127
+ if (res.status === 401 && this.opts.getAccessToken) {
128
+ res = await this.send(method, path, options, true);
197
129
  }
198
130
  if (!res.ok) {
199
131
  const requestId = res.headers.get("x-request-id") ?? void 0;
200
132
  const message = await this.extractMessage(res);
201
- throw errorFromResponse(res.status, message, requestId);
133
+ throw errorFromResponse(
134
+ res.status,
135
+ message,
136
+ requestId,
137
+ parseRetryAfterMs(res.headers.get("retry-after"))
138
+ );
202
139
  }
203
140
  return res;
204
141
  }
205
- async send(method, path, options) {
206
- const token = await this.opts.tokenManager.getToken();
142
+ async send(method, path, options, forceRefresh = false) {
143
+ const token = await this.resolveToken(forceRefresh);
207
144
  const url = new URL(this.opts.apiBaseUrl + path);
208
145
  for (const [k, v] of Object.entries(options.query ?? {})) url.searchParams.set(k, v);
209
146
  const headers = {
@@ -225,6 +162,13 @@ var HttpClient = class {
225
162
  throw err;
226
163
  }
227
164
  }
165
+ async resolveToken(forceRefresh) {
166
+ const token = this.opts.getAccessToken ? await this.opts.getAccessToken(forceRefresh ? { forceRefresh: true } : void 0) : this.opts.accessToken;
167
+ if (!token) {
168
+ throw new DocmanaError("Missing Docmana access token", { code: "auth_missing" });
169
+ }
170
+ return token;
171
+ }
228
172
  async extractMessage(res) {
229
173
  try {
230
174
  const data = await res.clone().json();
@@ -234,6 +178,18 @@ var HttpClient = class {
234
178
  }
235
179
  }
236
180
  };
181
+ function parseRetryAfterMs(value) {
182
+ if (!value) return void 0;
183
+ const seconds = Number(value);
184
+ if (Number.isFinite(seconds) && seconds >= 0) {
185
+ return seconds * 1e3;
186
+ }
187
+ const retryAt = Date.parse(value);
188
+ if (!Number.isNaN(retryAt)) {
189
+ return Math.max(0, retryAt - Date.now());
190
+ }
191
+ return void 0;
192
+ }
237
193
 
238
194
  // src/files/resolve-input.ts
239
195
  import { readFile } from "fs/promises";
@@ -265,16 +221,19 @@ async function streamToBuffer(stream) {
265
221
  for await (const chunk of stream) chunks.push(Buffer.from(chunk));
266
222
  return Buffer.concat(chunks);
267
223
  }
224
+ function toBlobBytes(bytes) {
225
+ return new Uint8Array(bytes);
226
+ }
268
227
  async function resolveOne(input, fallbackName) {
269
228
  if (typeof input === "string" || isPathInput(input)) {
270
229
  const path = typeof input === "string" ? input : input.path;
271
230
  const data = await readFile(path);
272
231
  const filename = basename(path);
273
- return { data: new Blob([data]), filename, contentType: contentTypeFor(filename) };
232
+ return { data: new Blob([toBlobBytes(data)]), filename, contentType: contentTypeFor(filename) };
274
233
  }
275
234
  if (input instanceof Uint8Array) {
276
235
  return {
277
- data: new Blob([input]),
236
+ data: new Blob([toBlobBytes(input)]),
278
237
  filename: fallbackName,
279
238
  contentType: contentTypeFor(fallbackName)
280
239
  };
@@ -282,7 +241,7 @@ async function resolveOne(input, fallbackName) {
282
241
  if (isReadable(input)) {
283
242
  const buf = await streamToBuffer(input);
284
243
  return {
285
- data: new Blob([buf]),
244
+ data: new Blob([toBlobBytes(buf)]),
286
245
  filename: fallbackName,
287
246
  contentType: contentTypeFor(fallbackName)
288
247
  };
@@ -296,39 +255,43 @@ async function resolveInputs(input) {
296
255
  return Promise.all(list.map((item) => resolveOne(item, fallback)));
297
256
  }
298
257
 
299
- // src/api/upload.ts
300
- async function uploadFiles(http, parts, signal) {
258
+ // src/api/run-flow.ts
259
+ async function runFlow(http, flowId, parts, signal, useDraftVersion = false, context, callbackUrl, language) {
301
260
  const form = new FormData();
302
261
  for (const part of parts) {
303
262
  form.append("files", new File([part.data], part.filename, { type: part.contentType }));
304
263
  }
305
- const res = await http.requestJson("POST", "/upload", { body: form, signal });
306
- return [res.id];
307
- }
308
-
309
- // src/api/run-flow.ts
310
- async function runFlow(http, flowId, uuidFiles, signal, once = false, context, callbackUrl) {
311
- const path = once ? `/flows/run_once_flow/${flowId}` : `/flows/run_flow/${flowId}`;
312
- const body = { uuid_files: uuidFiles };
313
- if (context !== void 0) body.json_context = context;
314
- if (callbackUrl !== void 0) body.callback_url = callbackUrl;
315
- const res = await http.requestJson("POST", path, {
316
- query: { async_mode: "true" },
317
- headers: { "content-type": "application/json" },
318
- body: JSON.stringify(body),
319
- signal
320
- });
321
- return res.execution_result_id;
264
+ if (context !== void 0) form.append("json_context", JSON.stringify(context));
265
+ if (callbackUrl !== void 0) form.append("callback_url", callbackUrl);
266
+ if (language !== void 0) form.append("language", language);
267
+ if (useDraftVersion) form.append("useDraftVersion", "true");
268
+ return http.requestJson(
269
+ "POST",
270
+ `/flows/${flowId}/execute-async`,
271
+ { body: form, signal }
272
+ );
322
273
  }
323
274
 
324
275
  // src/api/execution-status.ts
325
276
  async function getStatus(http, executionResultId, signal) {
326
- return http.requestJson("GET", `/flows/execution-status/${executionResultId}`, { signal });
277
+ const res = await http.requestRaw("GET", `/executions/${executionResultId}/status`, { signal });
278
+ const text = await res.text();
279
+ const body = text ? JSON.parse(text) : { status: "" };
280
+ const pollAfterMs = parsePositiveInt(res.headers.get("x-poll-after"));
281
+ return pollAfterMs === void 0 ? body : { ...body, pollAfterMs };
282
+ }
283
+ function parsePositiveInt(value) {
284
+ if (!value) return void 0;
285
+ const parsed = Number(value);
286
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
327
287
  }
328
288
 
329
289
  // src/api/execution-result.ts
330
- async function getResult(http, executionResultId, signal) {
331
- return http.requestJson("GET", `/flows/execution-result/${executionResultId}`, { signal });
290
+ async function getResult(http, executionResultId, signal, language) {
291
+ return http.requestJson("GET", `/executions/${executionResultId}/result`, {
292
+ query: language ? { language } : void 0,
293
+ signal
294
+ });
332
295
  }
333
296
 
334
297
  // src/polling/poll.ts
@@ -338,166 +301,42 @@ async function pollUntilTerminal(opts) {
338
301
  const sleep = opts.sleep ?? defaultSleep;
339
302
  const start = Date.now();
340
303
  const elapsed = opts.elapsed ?? (() => Date.now() - start);
304
+ const random = opts.random ?? Math.random;
305
+ let fallbackAttempt = 0;
341
306
  for (; ; ) {
342
307
  if (opts.signal?.aborted) throw new DocmanaAbortError("Polling aborted");
343
- const status = await opts.check();
308
+ let result;
309
+ try {
310
+ result = normalizePollResult(await opts.check());
311
+ } catch (err) {
312
+ if (!(err instanceof DocmanaRateLimitError)) throw err;
313
+ if (elapsed() >= opts.timeoutMs) {
314
+ throw new DocmanaTimeoutError(`Execution did not finish within ${opts.timeoutMs}ms`);
315
+ }
316
+ await sleep(err.retryAfterMs ?? opts.intervalMs);
317
+ continue;
318
+ }
319
+ const { status } = result;
344
320
  if (TERMINAL.has(status)) return status;
345
321
  if (elapsed() >= opts.timeoutMs) {
346
322
  throw new DocmanaTimeoutError(`Execution did not finish within ${opts.timeoutMs}ms`);
347
323
  }
348
- await sleep(opts.intervalMs);
324
+ const fallbackDelay = fullJitterDelay(
325
+ opts.intervalMs,
326
+ opts.maxIntervalMs,
327
+ fallbackAttempt,
328
+ random
329
+ );
330
+ fallbackAttempt += 1;
331
+ await sleep(result.nextDelayMs ?? fallbackDelay);
349
332
  }
350
333
  }
351
-
352
- // src/mappers/mapper.ts
353
- function extractNodeFields(rawNode, targetLanguage) {
354
- const metadataFields = /* @__PURE__ */ new Set([
355
- "node_id",
356
- "node_name",
357
- "node_type",
358
- "feature_name",
359
- "running_time",
360
- "status",
361
- "score",
362
- "feedback",
363
- "translations",
364
- "tokens",
365
- "input_tokens",
366
- "output_tokens",
367
- "errors",
368
- "mana",
369
- "model",
370
- "tool_calls",
371
- "prompt_id",
372
- "prompt",
373
- "prompt_name",
374
- "label",
375
- "scoreDescription",
376
- "score_description",
377
- "result",
378
- "documentType"
379
- ]);
380
- let sourceObj = rawNode;
381
- if (targetLanguage) {
382
- const translations = rawNode.translations;
383
- if (!translations || !translations[targetLanguage]) {
384
- throw new DocmanaError(
385
- `Translation for language '${targetLanguage}' is missing on node '${rawNode.node_name || rawNode.node_id}'`,
386
- { code: "translation_missing", status: 400 }
387
- );
388
- }
389
- sourceObj = translations[targetLanguage];
390
- }
391
- const dynamicFields = {};
392
- for (const [key, value] of Object.entries(sourceObj)) {
393
- if (!metadataFields.has(key)) {
394
- dynamicFields[key] = value;
395
- }
396
- }
397
- const sdkNode = {
398
- status: rawNode.status || "Unknown"
399
- };
400
- if (rawNode.errors && rawNode.errors.length > 0) {
401
- sdkNode.errors = rawNode.errors;
402
- }
403
- const nodeType = rawNode.node_type || "";
404
- const isScoreNode = /^(Validation|Classification|CrossValidation|Conclusion|Finish)$/i.test(
405
- nodeType
406
- );
407
- if (isScoreNode && rawNode.score !== void 0 && rawNode.score !== null) {
408
- sdkNode.score = rawNode.score;
409
- }
410
- const feedback = sourceObj.feedback ?? rawNode.feedback;
411
- if (feedback !== void 0 && feedback !== null) {
412
- sdkNode.feedback = feedback;
413
- }
414
- if (Object.keys(dynamicFields).length > 0) {
415
- sdkNode.data = dynamicFields;
416
- }
417
- return sdkNode;
334
+ function normalizePollResult(result) {
335
+ return typeof result === "string" ? { status: result } : result;
418
336
  }
419
- function mapExecutionResult(raw, targetLanguage) {
420
- const sdkResult = {
421
- status: raw.status || "Unknown",
422
- executionId: String(raw.execution_id || raw.executionResultId || raw.execution_result_id || ""),
423
- documents: {
424
- mappings: []
425
- }
426
- };
427
- if (raw.errors && raw.errors.length > 0) {
428
- sdkResult.errors = raw.errors;
429
- }
430
- const results = raw.results || [];
431
- for (const item of results) {
432
- const isDocSpecific = !!item.document;
433
- if (isDocSpecific && item.document) {
434
- const docReq = item.document;
435
- const docKey = docReq.doc_key || "unknown_doc";
436
- const docName = docReq.name || "";
437
- sdkResult.documents.mappings.push({
438
- name: docName,
439
- reference: docKey
440
- });
441
- const docResult = {
442
- status: item.status || docReq.status || "Unknown",
443
- extractions: {},
444
- validations: {}
445
- };
446
- const nodeResults = item.node_results || [];
447
- for (const node of nodeResults) {
448
- const nodeType = node.node_type || "";
449
- const nodeName = node.node_name || node.node_id || "unknown_node";
450
- if (/^Classification$/i.test(nodeType)) {
451
- const mappedNode = extractNodeFields(node, targetLanguage);
452
- if (!docResult.classifications) {
453
- docResult.classifications = {};
454
- }
455
- docResult.classifications[nodeName] = mappedNode;
456
- } else if (/^MetadataExtraction$/i.test(nodeType)) {
457
- docResult.metadataExtraction = extractNodeFields(node, targetLanguage);
458
- } else if (/^Extraction$/i.test(nodeType)) {
459
- if (docResult.extractions) {
460
- docResult.extractions[nodeName] = extractNodeFields(node, targetLanguage);
461
- }
462
- } else if (/^Validation$/i.test(nodeType)) {
463
- if (docResult.validations) {
464
- docResult.validations[nodeName] = extractNodeFields(node, targetLanguage);
465
- }
466
- }
467
- }
468
- if (docResult.extractions && Object.keys(docResult.extractions).length === 0) {
469
- delete docResult.extractions;
470
- }
471
- if (docResult.validations && Object.keys(docResult.validations).length === 0) {
472
- delete docResult.validations;
473
- }
474
- sdkResult.documents[docKey] = docResult;
475
- } else {
476
- const nodeResults = item.node_results || [];
477
- for (const node of nodeResults) {
478
- const nodeType = node.node_type || "";
479
- const nodeName = node.node_name || node.node_id || "unknown_node";
480
- if (/^CrossValidation$/i.test(nodeType)) {
481
- if (!sdkResult.crossValidations) {
482
- sdkResult.crossValidations = {};
483
- }
484
- sdkResult.crossValidations[nodeName] = extractNodeFields(
485
- node,
486
- targetLanguage
487
- );
488
- } else if (/^(Conclusion|Finish)$/i.test(nodeType)) {
489
- if (!sdkResult.conclusions) {
490
- sdkResult.conclusions = {};
491
- }
492
- sdkResult.conclusions[nodeName] = extractNodeFields(
493
- node,
494
- targetLanguage
495
- );
496
- }
497
- }
498
- }
499
- }
500
- return sdkResult;
337
+ function fullJitterDelay(intervalMs, maxIntervalMs, attempt, random) {
338
+ const capDelay = Math.min(maxIntervalMs, intervalMs * 2 ** attempt);
339
+ return Math.round(intervalMs + random() * (capDelay - intervalMs));
501
340
  }
502
341
 
503
342
  // src/client.ts
@@ -506,60 +345,79 @@ var Docmana = class {
506
345
  http;
507
346
  constructor(config) {
508
347
  this.config = resolveConfig(config);
509
- const tokenManager = new TokenManager({
510
- clientId: this.config.clientId,
511
- clientSecret: this.config.clientSecret,
512
- tokenEndpoint: this.config.tokenEndpoint,
513
- scope: this.config.scope,
514
- fetchImpl: this.config.fetchImpl,
515
- tokenCache: this.config.tokenCache
516
- });
517
348
  this.http = new HttpClient({
518
349
  apiBaseUrl: this.config.apiBaseUrl,
519
350
  fetchImpl: this.config.fetchImpl,
520
- tokenManager,
351
+ accessToken: this.config.accessToken,
352
+ getAccessToken: this.config.getAccessToken,
521
353
  headers: this.config.headers
522
354
  });
523
355
  }
524
356
  async runFlowAsync(flowId, input) {
525
357
  const parts = await resolveInputs(input);
526
- const fileIds = await uploadFiles(this.http, parts, input.signal);
527
- const executionResultId = await runFlow(
358
+ return runFlow(
528
359
  this.http,
529
360
  flowId,
530
- fileIds,
361
+ parts,
531
362
  input.signal,
532
- input.once ?? false,
533
- input.context
363
+ input.useDraftVersion ?? false,
364
+ input.context,
365
+ void 0,
366
+ input.language
534
367
  );
535
- return { executionResultId, fileIds };
536
368
  }
537
369
  async runFlowWithCallback(flowId, input) {
538
370
  const parts = await resolveInputs(input);
539
- const fileIds = await uploadFiles(this.http, parts, input.signal);
540
- const executionResultId = await runFlow(
371
+ return runFlow(
541
372
  this.http,
542
373
  flowId,
543
- fileIds,
374
+ parts,
544
375
  input.signal,
545
- input.once ?? false,
376
+ input.useDraftVersion ?? false,
546
377
  input.context,
547
- input.callbackUrl
378
+ input.callbackUrl,
379
+ input.language
548
380
  );
549
- return { executionResultId, fileIds };
550
381
  }
551
382
  async getStatus(executionResultId, signal) {
552
383
  return getStatus(this.http, executionResultId, signal);
553
384
  }
554
385
  async getResult(executionResultId, signal, language) {
555
- const rawResult = await getResult(this.http, executionResultId, signal);
556
- return mapExecutionResult(rawResult, language);
386
+ return getResult(this.http, executionResultId, signal, language);
557
387
  }
558
388
  async runFlow(flowId, input) {
559
389
  const { executionResultId } = await this.runFlowAsync(flowId, input);
390
+ let attempt = 0;
391
+ const startedAt = Date.now();
560
392
  await pollUntilTerminal({
561
- check: async () => (await this.getStatus(executionResultId, input.signal)).status,
393
+ check: async () => {
394
+ attempt += 1;
395
+ try {
396
+ const statusResult = await this.getStatus(executionResultId, input.signal);
397
+ const status = statusResult.status;
398
+ const nextPollAfterMs = this.isTerminalStatus(status) ? void 0 : statusResult.pollAfterMs;
399
+ input.onPoll?.({
400
+ executionResultId,
401
+ status,
402
+ attempt,
403
+ elapsedMs: Date.now() - startedAt,
404
+ nextPollAfterMs
405
+ });
406
+ return { status, nextDelayMs: nextPollAfterMs };
407
+ } catch (err) {
408
+ if (err instanceof DocmanaRateLimitError) {
409
+ input.onRateLimit?.({
410
+ executionResultId,
411
+ attempt,
412
+ elapsedMs: Date.now() - startedAt,
413
+ retryAfterMs: err.retryAfterMs ?? input.pollIntervalMs ?? this.config.pollIntervalMs
414
+ });
415
+ }
416
+ throw err;
417
+ }
418
+ },
562
419
  intervalMs: input.pollIntervalMs ?? this.config.pollIntervalMs,
420
+ maxIntervalMs: input.pollMaxIntervalMs ?? this.config.pollMaxIntervalMs,
563
421
  timeoutMs: input.timeoutMs ?? this.config.timeoutMs,
564
422
  signal: input.signal
565
423
  });
@@ -573,6 +431,9 @@ var Docmana = class {
573
431
  }
574
432
  return result;
575
433
  }
434
+ isTerminalStatus(status) {
435
+ return status === "Completed" || status === "Failed";
436
+ }
576
437
  };
577
438
  export {
578
439
  Docmana,