@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.
- package/README.md +115 -247
- package/dist/api/execution-result.d.ts +3 -0
- package/dist/api/execution-status.d.ts +6 -0
- package/dist/api/run-flow.d.ts +6 -0
- package/dist/cli.mjs +217 -257
- package/dist/cli.mjs.map +1 -1
- package/dist/client.d.ts +21 -0
- package/dist/config.d.ts +21 -0
- package/dist/errors.d.ts +55 -0
- package/dist/files/resolve-input.d.ts +11 -0
- package/dist/http/http-client.d.ts +26 -0
- package/dist/index.d.ts +4 -349
- package/dist/index.js +159 -298
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +159 -298
- package/dist/index.mjs.map +1 -1
- package/dist/models/docmana-api-document-execution-result.model.d.ts +9 -0
- package/dist/models/docmana-api-document-request.model.d.ts +15 -0
- package/dist/models/docmana-api-execution-result.model.d.ts +24 -0
- package/dist/models/docmana-api-node-result.model.d.ts +28 -0
- package/dist/models/docmana-classification-result.model.d.ts +3 -0
- package/dist/models/docmana-conclusion-result.model.d.ts +3 -0
- package/dist/models/docmana-cross-validation-result.model.d.ts +3 -0
- package/dist/models/docmana-document-mapping.model.d.ts +4 -0
- package/dist/models/docmana-document-result.model.d.ts +11 -0
- package/dist/models/docmana-execution-result.model.d.ts +15 -0
- package/dist/models/docmana-extraction-result.model.d.ts +3 -0
- package/dist/models/docmana-metadata-extraction-result.model.d.ts +3 -0
- package/dist/models/docmana-node-result.model.d.ts +7 -0
- package/dist/models/docmana-score-node-result.model.d.ts +5 -0
- package/dist/models/docmana-validation-result.model.d.ts +3 -0
- package/dist/models/document-content.model.d.ts +4 -0
- package/dist/models/execution-progress.model.d.ts +4 -0
- package/dist/models/execution-status.enum.d.ts +1 -0
- package/dist/models/flow-configs.model.d.ts +16 -0
- package/dist/models/flow-edge.model.d.ts +4 -0
- package/dist/models/flow-node-type.enum.d.ts +1 -0
- package/dist/models/flow-node.model.d.ts +33 -0
- package/dist/models/flow.model.d.ts +11 -0
- package/dist/models/index.d.ts +26 -0
- package/dist/models/node-translation-result.model.d.ts +7 -0
- package/dist/models/physical-document.model.d.ts +9 -0
- package/dist/models/virtual-document.model.d.ts +10 -0
- package/dist/polling/poll.d.ts +15 -0
- package/dist/types.d.ts +76 -0
- package/package.json +17 -14
- 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.
|
|
11
|
-
if (!config.
|
|
12
|
-
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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.
|
|
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/
|
|
300
|
-
async function
|
|
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
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
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", `/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
420
|
-
const
|
|
421
|
-
|
|
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
|
-
|
|
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
|
-
|
|
527
|
-
const executionResultId = await runFlow(
|
|
358
|
+
return runFlow(
|
|
528
359
|
this.http,
|
|
529
360
|
flowId,
|
|
530
|
-
|
|
361
|
+
parts,
|
|
531
362
|
input.signal,
|
|
532
|
-
input.
|
|
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
|
-
|
|
540
|
-
const executionResultId = await runFlow(
|
|
371
|
+
return runFlow(
|
|
541
372
|
this.http,
|
|
542
373
|
flowId,
|
|
543
|
-
|
|
374
|
+
parts,
|
|
544
375
|
input.signal,
|
|
545
|
-
input.
|
|
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
|
-
|
|
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 () =>
|
|
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,
|