@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.
- package/CHANGELOG.md +33 -4
- package/README.md +175 -232
- package/dist/api/execution-result.d.ts +3 -0
- package/dist/api/execution-status.d.ts +6 -0
- package/dist/api/flow-definition.d.ts +3 -0
- package/dist/api/flow-metadata.d.ts +3 -0
- package/dist/api/list-flows.d.ts +3 -0
- package/dist/api/list-organizations.d.ts +3 -0
- package/dist/api/organization-documents.d.ts +7 -0
- package/dist/api/run-flow.d.ts +6 -0
- package/dist/cli.mjs +1022 -695
- package/dist/cli.mjs.map +1 -1
- package/dist/client.d.ts +26 -0
- package/dist/config.d.ts +21 -0
- package/dist/errors.d.ts +55 -0
- package/dist/files/resolve-input.d.ts +9 -0
- package/dist/http/http-client.d.ts +31 -0
- package/dist/index.d.ts +4 -349
- package/dist/index.js +323 -339
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +319 -335
- 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 +145 -0
- package/package.json +17 -14
- 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
|
|
22
|
-
__export(
|
|
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(
|
|
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.
|
|
45
|
-
if (!config.
|
|
46
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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/
|
|
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.
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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 (
|
|
317
|
-
const
|
|
277
|
+
if (isNamedFileInput(input)) {
|
|
278
|
+
const bytes = input.data instanceof Uint8Array ? input.data : await streamToBuffer(input.data);
|
|
318
279
|
return {
|
|
319
|
-
data: new Blob([
|
|
320
|
-
filename:
|
|
321
|
-
contentType: contentTypeFor(
|
|
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
|
|
328
|
-
if (list.length === 0) throw new Error("runFlow requires `
|
|
329
|
-
|
|
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/
|
|
334
|
-
async function
|
|
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
|
-
|
|
340
|
-
|
|
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/
|
|
344
|
-
async function
|
|
345
|
-
|
|
346
|
-
|
|
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/
|
|
359
|
-
async function
|
|
360
|
-
|
|
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/
|
|
364
|
-
async function
|
|
365
|
-
|
|
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/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
454
|
-
const
|
|
455
|
-
|
|
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
|
-
|
|
498
|
+
accessToken: this.config.accessToken,
|
|
499
|
+
getAccessToken: this.config.getAccessToken,
|
|
555
500
|
headers: this.config.headers
|
|
556
501
|
});
|
|
557
502
|
}
|
|
558
|
-
async runFlowAsync(flowId,
|
|
559
|
-
const parts = await resolveInputs(
|
|
560
|
-
|
|
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
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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
|
-
|
|
590
|
-
return mapExecutionResult(rawResult, language);
|
|
520
|
+
return getResult(this.http, executionResultId, signal, language);
|
|
591
521
|
}
|
|
592
|
-
async runFlow(flowId,
|
|
593
|
-
const { executionResultId } = await this.runFlowAsync(flowId,
|
|
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 () =>
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
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,
|
|
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 = {
|