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