@docmana/sdk 0.3.4 → 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 (48) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +123 -211
  3. package/dist/api/execution-result.d.ts +3 -0
  4. package/dist/api/execution-status.d.ts +6 -0
  5. package/dist/api/run-flow.d.ts +6 -0
  6. package/dist/cli.mjs +225 -250
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/client.d.ts +21 -0
  9. package/dist/config.d.ts +21 -0
  10. package/dist/errors.d.ts +55 -0
  11. package/dist/files/resolve-input.d.ts +11 -0
  12. package/dist/http/http-client.d.ts +26 -0
  13. package/dist/index.d.ts +4 -335
  14. package/dist/index.js +167 -291
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +167 -291
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/models/docmana-api-document-execution-result.model.d.ts +9 -0
  19. package/dist/models/docmana-api-document-request.model.d.ts +15 -0
  20. package/dist/models/docmana-api-execution-result.model.d.ts +24 -0
  21. package/dist/models/docmana-api-node-result.model.d.ts +28 -0
  22. package/dist/models/docmana-classification-result.model.d.ts +3 -0
  23. package/dist/models/docmana-conclusion-result.model.d.ts +3 -0
  24. package/dist/models/docmana-cross-validation-result.model.d.ts +3 -0
  25. package/dist/models/docmana-document-mapping.model.d.ts +4 -0
  26. package/dist/models/docmana-document-result.model.d.ts +11 -0
  27. package/dist/models/docmana-execution-result.model.d.ts +15 -0
  28. package/dist/models/docmana-extraction-result.model.d.ts +3 -0
  29. package/dist/models/docmana-metadata-extraction-result.model.d.ts +3 -0
  30. package/dist/models/docmana-node-result.model.d.ts +7 -0
  31. package/dist/models/docmana-score-node-result.model.d.ts +5 -0
  32. package/dist/models/docmana-validation-result.model.d.ts +3 -0
  33. package/dist/models/document-content.model.d.ts +4 -0
  34. package/dist/models/execution-progress.model.d.ts +4 -0
  35. package/dist/models/execution-status.enum.d.ts +1 -0
  36. package/dist/models/flow-configs.model.d.ts +16 -0
  37. package/dist/models/flow-edge.model.d.ts +4 -0
  38. package/dist/models/flow-node-type.enum.d.ts +1 -0
  39. package/dist/models/flow-node.model.d.ts +33 -0
  40. package/dist/models/flow.model.d.ts +11 -0
  41. package/dist/models/index.d.ts +26 -0
  42. package/dist/models/node-translation-result.model.d.ts +7 -0
  43. package/dist/models/physical-document.model.d.ts +9 -0
  44. package/dist/models/virtual-document.model.d.ts +10 -0
  45. package/dist/polling/poll.d.ts +15 -0
  46. package/dist/types.d.ts +76 -0
  47. package/package.json +17 -14
  48. package/dist/index.d.cts +0 -335
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,38 +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) {
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
- const res = await http.requestJson("POST", path, {
315
- query: { async_mode: "true" },
316
- headers: { "content-type": "application/json" },
317
- body: JSON.stringify(body),
318
- signal
319
- });
320
- 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
+ );
321
273
  }
322
274
 
323
275
  // src/api/execution-status.ts
324
276
  async function getStatus(http, executionResultId, signal) {
325
- 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;
326
287
  }
327
288
 
328
289
  // src/api/execution-result.ts
329
- async function getResult(http, executionResultId, signal) {
330
- 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
+ });
331
295
  }
332
296
 
333
297
  // src/polling/poll.ts
@@ -337,166 +301,42 @@ async function pollUntilTerminal(opts) {
337
301
  const sleep = opts.sleep ?? defaultSleep;
338
302
  const start = Date.now();
339
303
  const elapsed = opts.elapsed ?? (() => Date.now() - start);
304
+ const random = opts.random ?? Math.random;
305
+ let fallbackAttempt = 0;
340
306
  for (; ; ) {
341
307
  if (opts.signal?.aborted) throw new DocmanaAbortError("Polling aborted");
342
- 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;
343
320
  if (TERMINAL.has(status)) return status;
344
321
  if (elapsed() >= opts.timeoutMs) {
345
322
  throw new DocmanaTimeoutError(`Execution did not finish within ${opts.timeoutMs}ms`);
346
323
  }
347
- 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);
348
332
  }
349
333
  }
350
-
351
- // src/mappers/mapper.ts
352
- function extractNodeFields(rawNode, targetLanguage) {
353
- const metadataFields = /* @__PURE__ */ new Set([
354
- "node_id",
355
- "node_name",
356
- "node_type",
357
- "feature_name",
358
- "running_time",
359
- "status",
360
- "score",
361
- "feedback",
362
- "translations",
363
- "tokens",
364
- "input_tokens",
365
- "output_tokens",
366
- "errors",
367
- "mana",
368
- "model",
369
- "tool_calls",
370
- "prompt_id",
371
- "prompt",
372
- "prompt_name",
373
- "label",
374
- "scoreDescription",
375
- "score_description",
376
- "result",
377
- "documentType"
378
- ]);
379
- let sourceObj = rawNode;
380
- if (targetLanguage) {
381
- const translations = rawNode.translations;
382
- if (!translations || !translations[targetLanguage]) {
383
- throw new DocmanaError(
384
- `Translation for language '${targetLanguage}' is missing on node '${rawNode.node_name || rawNode.node_id}'`,
385
- { code: "translation_missing", status: 400 }
386
- );
387
- }
388
- sourceObj = translations[targetLanguage];
389
- }
390
- const dynamicFields = {};
391
- for (const [key, value] of Object.entries(sourceObj)) {
392
- if (!metadataFields.has(key)) {
393
- dynamicFields[key] = value;
394
- }
395
- }
396
- const sdkNode = {
397
- status: rawNode.status || "Unknown"
398
- };
399
- if (rawNode.errors && rawNode.errors.length > 0) {
400
- sdkNode.errors = rawNode.errors;
401
- }
402
- const nodeType = rawNode.node_type || "";
403
- const isScoreNode = /^(Validation|Classification|CrossValidation|Conclusion|Finish)$/i.test(
404
- nodeType
405
- );
406
- if (isScoreNode && rawNode.score !== void 0 && rawNode.score !== null) {
407
- sdkNode.score = rawNode.score;
408
- }
409
- const feedback = sourceObj.feedback ?? rawNode.feedback;
410
- if (feedback !== void 0 && feedback !== null) {
411
- sdkNode.feedback = feedback;
412
- }
413
- if (Object.keys(dynamicFields).length > 0) {
414
- sdkNode.data = dynamicFields;
415
- }
416
- return sdkNode;
334
+ function normalizePollResult(result) {
335
+ return typeof result === "string" ? { status: result } : result;
417
336
  }
418
- function mapExecutionResult(raw, targetLanguage) {
419
- const sdkResult = {
420
- status: raw.status || "Unknown",
421
- executionId: String(raw.execution_id || raw.executionResultId || raw.execution_result_id || ""),
422
- documents: {
423
- mappings: []
424
- }
425
- };
426
- if (raw.errors && raw.errors.length > 0) {
427
- sdkResult.errors = raw.errors;
428
- }
429
- const results = raw.results || [];
430
- for (const item of results) {
431
- const isDocSpecific = !!item.document;
432
- if (isDocSpecific && item.document) {
433
- const docReq = item.document;
434
- const docKey = docReq.doc_key || "unknown_doc";
435
- const docName = docReq.name || "";
436
- sdkResult.documents.mappings.push({
437
- name: docName,
438
- reference: docKey
439
- });
440
- const docResult = {
441
- status: item.status || docReq.status || "Unknown",
442
- extractions: {},
443
- validations: {}
444
- };
445
- const nodeResults = item.node_results || [];
446
- for (const node of nodeResults) {
447
- const nodeType = node.node_type || "";
448
- const nodeName = node.node_name || node.node_id || "unknown_node";
449
- if (/^Classification$/i.test(nodeType)) {
450
- const mappedNode = extractNodeFields(node, targetLanguage);
451
- if (!docResult.classifications) {
452
- docResult.classifications = {};
453
- }
454
- docResult.classifications[nodeName] = mappedNode;
455
- } else if (/^MetadataExtraction$/i.test(nodeType)) {
456
- docResult.metadataExtraction = extractNodeFields(node, targetLanguage);
457
- } else if (/^Extraction$/i.test(nodeType)) {
458
- if (docResult.extractions) {
459
- docResult.extractions[nodeName] = extractNodeFields(node, targetLanguage);
460
- }
461
- } else if (/^Validation$/i.test(nodeType)) {
462
- if (docResult.validations) {
463
- docResult.validations[nodeName] = extractNodeFields(node, targetLanguage);
464
- }
465
- }
466
- }
467
- if (docResult.extractions && Object.keys(docResult.extractions).length === 0) {
468
- delete docResult.extractions;
469
- }
470
- if (docResult.validations && Object.keys(docResult.validations).length === 0) {
471
- delete docResult.validations;
472
- }
473
- sdkResult.documents[docKey] = docResult;
474
- } else {
475
- const nodeResults = item.node_results || [];
476
- for (const node of nodeResults) {
477
- const nodeType = node.node_type || "";
478
- const nodeName = node.node_name || node.node_id || "unknown_node";
479
- if (/^CrossValidation$/i.test(nodeType)) {
480
- if (!sdkResult.crossValidations) {
481
- sdkResult.crossValidations = {};
482
- }
483
- sdkResult.crossValidations[nodeName] = extractNodeFields(
484
- node,
485
- targetLanguage
486
- );
487
- } else if (/^(Conclusion|Finish)$/i.test(nodeType)) {
488
- if (!sdkResult.conclusions) {
489
- sdkResult.conclusions = {};
490
- }
491
- sdkResult.conclusions[nodeName] = extractNodeFields(
492
- node,
493
- targetLanguage
494
- );
495
- }
496
- }
497
- }
498
- }
499
- 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));
500
340
  }
501
341
 
502
342
  // src/client.ts
@@ -505,46 +345,79 @@ var Docmana = class {
505
345
  http;
506
346
  constructor(config) {
507
347
  this.config = resolveConfig(config);
508
- const tokenManager = new TokenManager({
509
- clientId: this.config.clientId,
510
- clientSecret: this.config.clientSecret,
511
- tokenEndpoint: this.config.tokenEndpoint,
512
- scope: this.config.scope,
513
- fetchImpl: this.config.fetchImpl,
514
- tokenCache: this.config.tokenCache
515
- });
516
348
  this.http = new HttpClient({
517
349
  apiBaseUrl: this.config.apiBaseUrl,
518
350
  fetchImpl: this.config.fetchImpl,
519
- tokenManager,
351
+ accessToken: this.config.accessToken,
352
+ getAccessToken: this.config.getAccessToken,
520
353
  headers: this.config.headers
521
354
  });
522
355
  }
523
356
  async runFlowAsync(flowId, input) {
524
357
  const parts = await resolveInputs(input);
525
- const fileIds = await uploadFiles(this.http, parts, input.signal);
526
- const executionResultId = await runFlow(
358
+ return runFlow(
527
359
  this.http,
528
360
  flowId,
529
- fileIds,
361
+ parts,
530
362
  input.signal,
531
- input.once ?? false,
532
- input.context
363
+ input.useDraftVersion ?? false,
364
+ input.context,
365
+ void 0,
366
+ input.language
367
+ );
368
+ }
369
+ async runFlowWithCallback(flowId, input) {
370
+ const parts = await resolveInputs(input);
371
+ return runFlow(
372
+ this.http,
373
+ flowId,
374
+ parts,
375
+ input.signal,
376
+ input.useDraftVersion ?? false,
377
+ input.context,
378
+ input.callbackUrl,
379
+ input.language
533
380
  );
534
- return { executionResultId, fileIds };
535
381
  }
536
382
  async getStatus(executionResultId, signal) {
537
383
  return getStatus(this.http, executionResultId, signal);
538
384
  }
539
385
  async getResult(executionResultId, signal, language) {
540
- const rawResult = await getResult(this.http, executionResultId, signal);
541
- return mapExecutionResult(rawResult, language);
386
+ return getResult(this.http, executionResultId, signal, language);
542
387
  }
543
388
  async runFlow(flowId, input) {
544
389
  const { executionResultId } = await this.runFlowAsync(flowId, input);
390
+ let attempt = 0;
391
+ const startedAt = Date.now();
545
392
  await pollUntilTerminal({
546
- 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
+ },
547
419
  intervalMs: input.pollIntervalMs ?? this.config.pollIntervalMs,
420
+ maxIntervalMs: input.pollMaxIntervalMs ?? this.config.pollMaxIntervalMs,
548
421
  timeoutMs: input.timeoutMs ?? this.config.timeoutMs,
549
422
  signal: input.signal
550
423
  });
@@ -558,6 +431,9 @@ var Docmana = class {
558
431
  }
559
432
  return result;
560
433
  }
434
+ isTerminalStatus(status) {
435
+ return status === "Completed" || status === "Failed";
436
+ }
561
437
  };
562
438
  export {
563
439
  Docmana,